Reputation: 19341
I am trying to combine two object based on keys given But, It become hard then expected.
const keys = ["year_and_month", "name"];
const firstData = [
{
"year_and_month": "2022-01",
"name": "Roy",
"data1": 3388560126.065652,
"data2": 889386921115.6444
},
{
"year_and_month": "2022-02",
"name": "Roy",
"data1": 3897475493.9987683,
"data2": 874308539354.9275
},
{
"year_and_month": "2022-02",
"name": "Dan",
"data1": 443961561.24720746,
"data2": 293742072318.20105
},
{
"year_and_month": "2022-01",
"name": "Dan",
"data1": 362316175.165702,
"data2": 303232994015.44
},
{
"year_and_month": "2022-02",
"name": "Tata",
"data1": 22744562.245873,
"data2": 790044572051.9896
},
{
"year_and_month": "2022-01",
"name": "Tata",
"data1": 22744562.245873,
"data2": 790044572051.9896
}
]
const secondData = [
{
"year_and_month": "2022-01",
"name": "Roy",
"data3": 4083741657.64,
"data4": 36693935225.96
},
{
"year_and_month": "2022-02",
"name": "Roy",
"data3": 2436561209.83,
"data4": 31013728462.63
},
{
"year_and_month": "2022-02",
"name": "Dan",
"data3": -8298497218.39,
"data4": 34817072736.04
},
{
"year_and_month": "2022-01",
"name": "Dan",
"data3": 1312315161.48,
"data4": 34790053142.56
},
{
"year_and_month": "2022-01",
"name": "Tata",
"data3": -745507724.01,
"data4": 13533928780.38
},
{
"year_and_month": "2022-02",
"name": "Tata",
"data3": 658173707,
"data4": 13282740718.8
}
]
//This way, don't find the way to move forward
//let firstKeys = [];
//let secondKeys = [];
//firstData.map(data => keys.forEach(key => firstKeys.push(data[key]) ));
//secondData.map(data => keys.forEach(key => secondKeys.push(data[key]) ));
//console.log(firstKeys);
//console.log(secondKeys);
//Tried Second way But, stuck again
const result = secondData.reduce((res, ele) => {
console.log(ele);
keys.forEach(key => {
firstData.find(data => data[key] === ele[key]);
})
return res
}, [])
console.log("result", result);
Expected Result (combine both array based on keys given like here match year_and_month and name):
[{
"year_and_month": "2022-01",
"name": "Roy",
"data1": 3388560126.065652,
"data2": 889386921115.6444,
"data3": 4083741657.64,
"data4": 36693935225.96
},
{
"year_and_month": "2022-02",
"name": "Roy",
"data1": 3897475493.9987683,
"data2": 874308539354.9275,
"data3": -8298497218.39,
"data4": 34817072736.04
}
... and so on
]
Upvotes: 1
Views: 117
Reputation: 158
This is a good use case for the built-in Map data structure, in whose key-value pairs we can have strings as keys.
The idea is to conceptually treat the pair (year_and_month, name) as a composite primary key, then turn it into a simple key to be used in a new Map entry whose value gets updated with more "data fields" (data1, data2, etc.) as we iterate over the Array inputs and find matching keys.
In order to update such a Map entry, we'll use spread operations inside a new object literal, then pass it to a call to Map.prototype.set()
.
In the end, the Map values will have the information we want, which can be coerced back into an Array.
/*
O(n)
Concatenates arrays, makes one pass & creates map entries as it goes.
Uses existing (year_and_month, name) pairs as map keys.
Finally, returns an array made from the map values.
*/
function mergeArrays(firstArray, secondArray) {
const map = new Map()
// for...of statement over Array, spread operator
for (const arrayValue of [...firstArray, ...secondArray]) {
const {
year_and_month,
name
} = arrayValue // destructuring assignment
const mapKey = [year_and_month, name].join(',')
const mapValue = map.get(mapKey)
map.set(mapKey, { ...mapValue,
...arrayValue
}) // spread operator
}
return Array.from(map.values())
}
const firstData = [{
year_and_month: '2022-01',
name: 'Roy',
data1: 3388560126.065652,
data2: 889386921115.6444,
},
{
year_and_month: '2022-02',
name: 'Roy',
data1: 3897475493.9987683,
data2: 874308539354.9275,
},
{
year_and_month: '2022-02',
name: 'Dan',
data1: 443961561.24720746,
data2: 293742072318.20105,
},
{
year_and_month: '2022-01',
name: 'Dan',
data1: 362316175.165702,
data2: 303232994015.44,
},
{
year_and_month: '2022-02',
name: 'Tata',
data1: 22744562.245873,
data2: 790044572051.9896,
},
{
year_and_month: '2022-01',
name: 'Tata',
data1: 22744562.245873,
data2: 790044572051.9896,
},
]
const secondData = [{
year_and_month: '2022-01',
name: 'Roy',
data3: 4083741657.64,
data4: 36693935225.96,
},
{
year_and_month: '2022-02',
name: 'Roy',
data3: 2436561209.83,
data4: 31013728462.63,
},
{
year_and_month: '2022-02',
name: 'Dan',
data3: -8298497218.39,
data4: 34817072736.04,
},
{
year_and_month: '2022-01',
name: 'Dan',
data3: 1312315161.48,
data4: 34790053142.56,
},
{
year_and_month: '2022-01',
name: 'Tata',
data3: -745507724.01,
data4: 13533928780.38,
},
{
year_and_month: '2022-02',
name: 'Tata',
data3: 658173707,
data4: 13282740718.8,
},
]
console.log(mergeArrays(firstData, secondData))
I ran all the answers through 100.000 sized inputs and got the following execution times on my laptop:
61ms for call to david
284ms for call to lucianoFerraz
294ms for call to mattMorgan
47641ms for call to apurvaMistry
48969ms for call to yuceKilic
David's answer is by far the fastest, but unreliable if you can't guarantee that your array inputs will be symmetrical and equally ordered.
Mine and Matt's run in the middle with the same time complexity @ O(n), but without David's compromises.
Apurva & Yüce's take the longest to complete because they run @ O(n^2).
I hope that helps!
Upvotes: 1
Reputation: 5303
Here's a possible approach that relies on the supplied keys being strings. You could modify the extractKey
function as required. I've written it to take any number of keys, but if you only have two it could obviously be simplified.
This approach also does not make any attempt to sort the incoming fields or sort the output according to name and date.
Finally, there are definitely some optimizations that could be made, including memoizing the key computation if you had a large dataset, and storing those in a hash table.
const keys = ["year_and_month", "name"];
const firstData = [{
"year_and_month": "2022-01",
"name": "Roy",
"data1": 3388560126.065652,
"data2": 889386921115.6444
},
{
"year_and_month": "2022-02",
"name": "Roy",
"data1": 3897475493.9987683,
"data2": 874308539354.9275
},
{
"year_and_month": "2022-02",
"name": "Dan",
"data1": 443961561.24720746,
"data2": 293742072318.20105
},
{
"year_and_month": "2022-01",
"name": "Dan",
"data1": 362316175.165702,
"data2": 303232994015.44
},
{
"year_and_month": "2022-02",
"name": "Tata",
"data1": 22744562.245873,
"data2": 790044572051.9896
},
{
"year_and_month": "2022-01",
"name": "Tata",
"data1": 22744562.245873,
"data2": 790044572051.9896
}
]
const secondData = [{
"year_and_month": "2022-01",
"name": "Roy",
"data3": 4083741657.64,
"data4": 36693935225.96
},
{
"year_and_month": "2022-02",
"name": "Roy",
"data3": 2436561209.83,
"data4": 31013728462.63
},
{
"year_and_month": "2022-02",
"name": "Dan",
"data3": -8298497218.39,
"data4": 34817072736.04
},
{
"year_and_month": "2022-01",
"name": "Dan",
"data3": 1312315161.48,
"data4": 34790053142.56
},
{
"year_and_month": "2022-01",
"name": "Tata",
"data3": -745507724.01,
"data4": 13533928780.38
},
{
"year_and_month": "2022-02",
"name": "Tata",
"data3": 658173707,
"data4": 13282740718.8
}
]
// You need a function that will extract a unique and stable key
// for each combination of name and date.
function extractKey(obj, keys) {
return keys.reduce((compoundKey, key) => {
return compoundKey + obj[key];
}, "");
}
// Iterate over all the data, binning the objects by their compound keys.
// Your results will be the array of values.
const results = Object.values([...firstData, ...secondData].reduce((map, datum) => {
const key = extractKey(datum, keys);
if (map[key]) {
// In the case that we've seen this key already,
// the object spread merges the fields from the
// current object into the existing data.
map[key] = {...map[key], ...datum};
} else {
// If we haven't seen this key before, we just
// store the current object as the only entry for
// that name and date.
map[key] = {...datum};
}
return map;
}, {}));
console.log(results);
Upvotes: 1
Reputation: 59
const result = firstData.map((firstEl) => {
const secondEl = secondData.find((el) =>
keys.every((key) => firstEl[key] === el[key])
);
return { ...firstEl, ...secondEl };
});
Explanation: Map all the elements from firstData
, find their match (that has the same values in given keys) in secondData
and merge them using spread operator (...)
Note: Be careful on comparing non-primitive values.
Upvotes: 2
Reputation: 114
If your two arrays have the same length and are sorted in the same way, you can combine the nested objects with Object.assign:
const result = firstData.map((obj, i) => (Object.assign(obj, secondData[i])));
Upvotes: 2
Reputation: 126
Try if this helps:
const combinedData = firstData.map(item => {
return {
...item,
...(secondData.find(secondItem => secondItem.year_and_month === item.year_and_month && secondItem.name === item.name))
}
})
Upvotes: 2