JavaScript Finding/Comparing and updating duplicate elements of metric/multi dimension array - javascript

I have a metric/multi dimension array like below
[
[a,b,c,d],
[d,a,c,b],
[a,d,b,a],
[c,c,d,a]
]
I am required to update my given metric and keep track of change in a such a way
An element can repeat itself in one column only.
An element can not occur in other columns if it has occurred in a column.
If the above condition occur update the element by appending the column index to all its occurrence in a column.
In the above example element at index [1][1]('a' in row 2 and column 2) has occur in column 1. It and all its occurrence should update to 'a1'. Similarly 'd' and 'c' should update to 'd1' and 'c1' respectively.
In the next column Column 3, 'c', 'b', 'd' in column 3 should update to 'c2','b2','d2' because 'b' has occurred is column 2, similarly 'c' and 'd' has occurred before.
In next column Column 4 'd','b','a' will update to 'd4','b4','a4'.
Resulted metric will look like
[
[a,b, c3,d4],
[d,a2,c3,b4],
[a,d2,b3,a4],
[c,c2,d3,a4]
]
Keep track part
we can keep track like
var dictionary = [{"updatedValue":"originalValue"},...]
var dictionary = [{"a2":"a"},{"d2","d"},{"c2","c"},{"c3":"c"},{"b3":"b"},{"d3":"d"},{"d4","d"},{"a4":"a"},{"b4","b"}];
so far I have tried this
var flatData = [
['a', 'b', 'c', 'd'],
['d', 'a', 'c', 'b'],
['a', 'd', 'b', 'a'],
['c', 'c', 'd', 'a'],
];
for (var i = 0; i < flatData.length; i++) {
for (var j = 0; j < flatData[i].length; j++) {
var element = flatData[i][j];
for (var k = 0; k < flatData.length; k++) {
for (var l = 0; l < flatData[k].length; l++) {
if (j != l) {
if (element == flatData[k][l]) {
flatData[k][l] = flatData[k][l] + l;
}
}
}
}
}
}
console.log(JSON.stringify(flatData));

Solution uses a Map(could be plain object also) where first time a value is encountered a new entry is created that has an object {col: firstColIndexFound, count:0}.
Next time same value is encountered it checks stored column index and if different updates the count and creates a new value
const data = [
['a', 'b', 'c', 'd'],
['d', 'a', 'c', 'b'],
['a', 'd', 'b', 'a'],
['c', 'c', 'd', 'a']
];
const dict = {};
const map = new Map();
for (let c = 0; c < data[0].length; c++) { // c for colIndex
for (let r = 0; r < data.length; r++) { // r for rowIndex
const el = data[r][c];
if (!map.has(el)) {
// first time found create new entry
map.set(el, {col: c, count: 0});
}
const entry = map.get(el);
// if column index different than first column found update value
if (c !== entry.col) {
entry.count++;
const nVal = el + entry.count;
dict[nVal] = el;
data[r][c] = nVal;
}
}
}
console.log(JSON.stringify(data))
console.log(dict)
.as-console-wrapper {
max-height: 100%!important;
top: 0;
}

Related

How to group every 2nd and 3rd items of an array into sub-arrays?

I have an array of objects
const objects = [a, b, c, d, e, f, g ... ]
and I want them to turn into
const result = [a, [b, c], d, [e, f], g ... ]
Any ideas?
[Edit] My apologies. This is my first post, didn't know I have to show my attempts. I don't think I deserve the mean comments either, be nice people. I solved it after a head-banging 4 hours. Here is my solution:
const result = []
const method = array => {
for (let i = 0; i < array.length; i += 3) {
const set = new Set([array[i + 1], array[i + 2]])
if (i !== array.length - 1) {
result.push(array[i])
result.push(Array.from(set))
} else {
result.push(array[i])
}
}
}
Thanks for the responses guys! I read every single one of them.
You could take a while loop and push either an item or a pair of items.
var array = ['a', 'b', 'c', 'd', 'e', 'f', 'g'],
grouped = [],
i = 0;
while (i < array.length) {
grouped.push(array[i++]);
if (i >= array.length) break;
grouped.push(array.slice(i, i += 2));
}
console.log(grouped);
You can do this with plain for loop and % modulo operator.
const objects = ['a', 'b', 'c', 'd', 'e', 'f', 'g']
const result = []
for(let i = 0; i < objects.length; i++) {
if(i % 3 === 0) {
const arr = objects.slice(i + 1, i + 3)
result.push(objects[i])
if(arr.length) result.push(arr)
}
}
console.log(result)
this is my solution:
const objects = ["a", "b", "c", "d", "e", "f", "g"];
let result = [];
let toGroup = false;
for(let i = 0; i < objects.length ; i++){
if(toGroup){
result.push([objects[i], objects[++i]]);
}
else result.push(objects[i]);
toGroup = !toGroup;
}
this has a particular case that you have not specified, where it doesn't work, for example if inside objects there are 2 elements, and so i don't know what you would like to do in that case

Avoid adding element to array if it's been added before

I have a very hard time formulating my question, I hope you guys understand what I mean.
Is there a way to make sure elements never end up together again?
Example, If A, B, C and D has been in the same new array before, they shouldn't be able to be together again.
This is my code,
let xGrps = 3; // Number of groups
let xSize = 4; // Number of items per group
let allItems = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L']; // All Items
let newGrps = []; // New groups
for (let i = 0; i < xGrps; i++) {
let tempGrp = "";
for(let j = 0; j < xSize; j++) {
tempGrp += allItems[0] + ",";
allItems.shift();
}
newGrps[i] = tempGrp;
console.log(newGrps[i]);
}
I belive I should use something like this maybe,
let blockGrps = [{
A: ['B'],
B: ['C','D'],
C: ['E'],
// and so on
}];

Why are the other chunks of the array being ignored?

function chunk(arr, size) {
var newr = [];
var temp = [];
for (var i = 0; i < arr.length; i++) {
if (temp.length != size) {
temp.push(arr[i]);
} else {
newr.push(temp);
temp = [];
}
}
return newr;
}
chunk(['a', 'b', 'c', 'd'], 2);
Can someone help me why my code isn't working? It's just displaying the first chunk of array and ignoring the second.
Here is one efficient way of doing it using Array.splice():
function chunk(arr, size) {
var out = [];
while(arr.length) out.push(arr.splice(0, size));
return out;
}
Calling chunk(['a', 'b', 'c', 'd'], 2); will return:
[
["a", "b"],
["c", "d"]
]
Note: The above method will modify the original array that is passed into the function.
To fix your code, try this
function chunk(arr, size) {
var newr = [];
var temp = [];
for (var i = 0; i < arr.length; i++) {
temp.push(arr[i]);
if(temp.length==size || i==arr.length-1) {
newr.push(temp);
temp = [];
}
}
return newr;
}
chunk(['a', 'b', 'c', 'd'], 2); // results in [['a','b'],['c','d']]
chunk(['a', 'b', 'c', 'd', 'e'], 2); // results in [['a','b'],['c','d'],['e']]
Why your previous code doesn't work
Your condition works well. The last iteration does collect the last chunk ['c','d'] in temp correctly but it is not added to the newr list. Thus, a little modification to cover this issue is made in my code as shown above.

javascript array format via for loop

What I am doing wrong here? I am getting TypeError: items[i] is undefined as the error.
var items = [];
for(var i = 1; i <= 3; i++){
items[i].push('a', 'b', 'c');
}
console.log(items);
I need an output as given below,
[
['a', 'b', 'c'],
['a', 'b', 'c'],
['a', 'b', 'c']
]
You could simply use the following:
items.push(['a', 'b', 'c']);
No need to access the array using the index, just push another array in.
The .push() method will automatically add it to the end of the array.
var items = [];
for(var i = 1; i <= 3; i++){
items.push(['a', 'b', 'c']);
}
console.log(items);
As a side note, it's worth pointing out that the following would have worked:
var items = [];
for(var i = 1; i <= 3; i++){
items[i] = []; // Define the array so that you aren't pushing to an undefined object.
items[i].push('a', 'b', 'c');
}
console.log(items);

How to get all unique elements in for an array of array but keep max count of duplicates

The question doesn't make much sense but not sure how to word it without an example. If someone can word it better, feel free to edit it.
Let's say I have an array of arrays such as this:
[ ['a', 'a', 'b', 'c'], [], ['d', 'a'], ['b', 'b', 'b', 'e'] ]
I would like the output to be:
['a', 'a', 'b', 'b', 'b', 'c', 'd', 'e']
Not sure if there is an easy way to do this in javascript/jquery/underscore. One way I could think of is to look through each of these arrays and count up the number of times each element shows up and keep track of the maximum amount of times it shows up. Then I can recreate it. But that seems pretty slow considering that my arrays can be very large.
You need to:
Loop over each inner array and count the values
Store each value and its count (if higher than current count) in a counter variable
In the end, convert the value and counts into an array
Following code shows a rough outline of the process. Remember to replace .forEach and for..in with appropriate code:
var input = [['a', 'a', 'b', 'c'], [], ['d', 'a'], ['b', 'b', 'b', 'e']],
inputCount = {};
input.forEach(function(inner) {
var innerCount = {};
inner.forEach(function(value) {
innerCount[value] = innerCount[value] ? innerCount[value] + 1 : 1;
});
var value;
for (value in innerCount) {
inputCount[value] = inputCount[value] ? Math.max(inputCount[value], innerCount[value]) : innerCount[value];
}
});
console.log(inputCount);
// Object {a: 2, b: 3, c: 1, d: 1, e: 1}
After messing around, I found a solution but not sure if I like it enough to use. I would probably use it if I can't think of another one.
I would use underscorejs countBy to get the count of all the elements.
var array = [ ['a', 'a', 'b', 'c'], [], ['d', 'a'], ['b', 'b', 'b', 'e'] ];
var count = _.map(array, function(inner) {
return _.countBy(inner, function(element) {
return element;
});
});
var total = {};
_.each(_.uniq(_.flatten(array)), function(element) {
var max = _.max(count, function(countedElement) {
return countedElement[element];
});
total[element] = max[element];
});
console.log(total); // {a: 2, b: 3, c: 1, d: 1, e: 1}
Then I would recreate the array with that total.
Here is example of simple nested loop approach:
var input = [ ['a', 'a', 'b', 'c'], [], ['d', 'a'], ['b', 'b', 'b', 'e'] ];
var countMap = {};
// iterate outer array
for (i=0; i < input.length; i++) {
// iterate inner array
for (j=0; j < input[i].length; j++) {
// increment map counter
var value = input[i][j];
if (countMap[input[i][j]] === undefined) {
countMap[value] = 1;
} else {
countMap[value]++;
}
}
}
console.log(countMap); // output such as {'a':2, 'b':4, 'c':1, 'd':1, 'e':1}
Not the most efficient solution but it should describe you the process:
var big = [ ['a', 'a', 'b', 'c'], [], ['d', 'a'], ['b', 'b', 'b', 'e'] ];
function map(arr){
var map = {}
for (var i=arr.length-1; i>-1; i--){
if(arr[i] in map) map[arr[i]]++;
else map[arr[i]] = 1;
}
return map;
}
function reduce(matrix){
var arrMap = {};
for (var i=matrix.length-1; i>-1; i--){
var arrRes = map(matrix[i]);
for (var key in arrRes){
if( !arrMap[key] || arrMap[key] < arrRes[key])
arrMap[key] = arrRes[key];
}
}
return arrMap;
}
function calc(matrix){
var res = [],
arrMap = reduce(matrix);
for (var key in arrMap){
while(arrMap[key] > 0 ){
res.push(key);
arrMap[key]--;
}
}
return res;
}
console.log(calc(big));
// Array [ "e", "b", "b", "b", "a", "a", "d", "c" ]

Categories