I have one array which has two values one date and an amount but there is the same date with a different value at a different index so I need to merge those values into the same date in a multidimensional javascript array
current array
var arry = [
['2021-05-01',100],
['2021-05-02',300],
['2021-05-03',200],
['2021-05-01',150],
['2021-05-02',300],
['2021-05-01',600],
['2021-05-04',120]
]
Expected Result Array
var arry = [
['2021-05-01',850],
['2021-05-02',600],
['2021-05-03',200],
['2021-05-04',120]]
Can anybody help? I really appreciate any help you can provide.
CodePudding user response:
You can use reduce
method:
var arry = [
['2021-05-01',100],
['2021-05-02',300],
['2021-05-03',200],
['2021-05-01',150],
['2021-05-02',300],
['2021-05-01',600],
['2021-05-04',120]
];
const data = arry.reduce((list, [date, value]) => {
list[date] = (list[date] ?? 0) value;
return list;
}, {});
const list = Object.entries(data); // if you want the array
console.log(list);
CodePudding user response:
Here is a solution using reduce
. I'm creating an object grouped by date and taking the values array of it
var arry = [['2021-05-01',100], ['2021-05-02',300], ['2021-05-03',200], ['2021-05-01',150],['2021-05-02',300], ['2021-05-01',600],['2021-05-04',120]]
const res = Object.values(arry.reduce((acc,[date,val])=> {
acc[date] = acc[date] || [date,0]
acc[date][1] =val
return acc
},{}))
console.log(res)
CodePudding user response:
You could likely just loop through the list, and at each value in the list check all of the values that came before to see if it is a repeat. Something like the following would work:
var array = [
['2021-05-01',100],
['2021-05-02',300],
['2021-05-03',200],
['2021-05-01',150],
['2021-05-02',300],
['2021-05-01',600],
['2021-05-04',120]
]
var newArray = []; // where we will put the new merged values
for (var lookAtOldArray = 0; lookAtOldArray < array.length; lookAtOldArray ) {
// check all previous values in newArray up to this point:
var checkNewArray; // declare out here for logic post loop
for (checkNewArray = 0; checkNewArray < newArray.length; checkNewArray ) {
if (array[lookAtOldArray][0] == newArray[checkNewArray][0]) {
// add to newArray number:
newArray[checkNewArray][1] = array[lookAtOldArray][1];
break; // BREAK to signify we found a position
}
// otherwise keep looking
}
// because of the break, if checkNewArray == newArray.length, then we DID NOT find a duplicate (AKA: push to newArray with exact value in array)
if (checkNewArray == newArray.length) {
newArray.push(array[lookAtOldArray]);
}
}
another interesting idea would be to use objects. The above strategy would require looking the data more times than necessary (n^2 for worst cases). With an object, you could use the date as a key, and the number as the value. With that, you could do something like this (assuming the same declaration of array
:
var combinedDates = {};
for (var lookAtOldArray = 0; lookAtOldArray < array.length; lookAtOldArray ) {
combinedDates[array[lookAtOldArray][0]] = array[lookAtOldArray[1];
}
You can tell this is a lot faster and simpler. The resulting object would look like this:
{
"2021-05-01": 850,
"2021-05-02": 600,
"2021-05-03": 200,
"2021-05-04": 120
}
I'm preferential to the second one because of the efficiency increase; you only ever have to look at each element in the initial array once (resulting in n
, or linear, time complexity)!
If you want to combine the above object back into an array, you could then do:
// get object keys
var objectKeys = Object.keys(combinedDates);
var newArray = [];
// loop through keys
for (var makeObject = 0; makeObject < objectKeys.length; makeObject ) {
// create array with key (the date) and the number (the value stored at the key):
newArray.push([objectKeys[makeObject][0], combinedDates[objectKeys[makeObject]]);
}