how to combine array of object fast or in optimized way - javascript

I have two Array of objects [{id:'KS001', name: 'albedo'}] this is the first array which consist of 900+ objects.
{
"changePoints": [
{
"Point": {
"name": "001",
"id": "KS001",
"siteID": "258628",
"connectorGroups": [
{
"connectorGroupID": 1,
"connectors": [
{
"connectorID": "1",
"connectorStatus": "AVAILABLE"
}
]
},
{
"connectorGroupID": 2,
"connectors": [
{
"connectorID": "2",
"connectorStatus": "AVAILABLE"
}
]
}
]
}
},
],
}
this is the second array that contains objects which have a point and id this id map with the first array as an identifier I need to check each connectorStatus in the second array with the corresponding id and add a new key to the first array status set "AVAILABLE" else not "NOT AVAILABLE"
I need to find the fastest way to do this

const object1 = {
name: 'Flavio'
}
const object2 = {
age: 35
}
const object3 = {...object1, ...object2 } //{name: "Flavio", age: 35}
const a = { b: 1, c: 2 };
const d = { e: 1, f: 2 };
const ad = { ...a, ...d }; // { b: 1, c: 2, e: 1, f: 2 }

Related

flatten array and put child array into an array of object

I struggled with a problem for more than an hour, how can I turn this nested array
[
[
{
"name": "1",
}
],
[
{
"name": "a",
},
{
"name": "b",
}
]
]
into this:
[
{
name: '1',
},
{
id: 'a-b',
grouped: [
{
name: 'a',
},
{
name: 'b',
},
],
},
]
I don't mind using lodash. Not sure should I flatten it before anything else would make things easier.
You could use map() to form the id and grab the parts needed to reconstruct the new array.
const data = [
[{
"name": "1",
}],
[{
"name": "a",
},
{
"name": "b",
}
]
];
const result = [
...data[0],
{
id: data[1].map(r => r.name).join("-"),
grouped: data[1]
}
];
console.log(result);
to flatten the array is a good start. That will remove the superfluous dimension from the rawArray:
const newArray = array.flat()
Now you have an array with three simple objects. The first will remain unchanged. The second element of your finalArray needs to be an object, so let's create it:
const obj = {}
the obj has two keys: id and grouped. The property of id is a string that we can create like this:
obj.id = newArray[1].name + "-" + newArray[2].name
the property of grouped remains the same:
obj.grouped = array[1]
so the finalArray is now straight forward:
const finalArray = [ newArray[0], obj ]
Put it all together in a function:
const rawArray1 = [
[
{
"name": "1a",
}
],
[
{
"name": "a",
},
{
"name": "b",
}
]
]
const rawArray2 = [
[
{
"name": "1b",
}
],
[
{
"name": "aa",
},
{
"name": "bb",
}
]
]
transformArray( rawArray1 )
transformArray( rawArray2 )
function transformArray( array ){
const newArray = array.flat()
const obj = {}
obj.id = newArray[1].name + "-" + newArray[2].name
obj.grouped = array[1]
const finalArray = [ newArray[0], obj ]
console.log(finalArray)
return finalArray
}
I managed to solve it using simple forEach, push, and flat. It's more simple than I thought, I was confused and stuck with map and reduce.
let result = [];
[
[{
"name": "1",
}],
[{
"name": "a",
},
{
"name": "b",
}
]
].forEach((val) => {
const [{
name
}] = val
if (val.length === 1) {
result.push({
name,
})
} else if (val.length > 1) {
result.push({
id: val.map(val2 => val2.name).join('-'),
grouped: val
})
}
})
console.log(result.flat())
const array1 = [
[{ name: "1" }],
[
{ name: "a" },
{ name: "b" }
]
]
const array2 = [
[{ name: "2" }],
[
{ name: "aa" },
{ name: "bb" },
{ name: "cc" }
]
]
transformArray( array1 )
transformArray( array2 )
function transformArray( array ){
const result = []
// destructure first array element for the first object:
const [ nameObj ] = array[0]
result.push( nameObj )
// map each object of the second array element into an
// an array of names, and then join the names together:
const dataObj = {}
dataObj.id = array[1].map(obj => obj.name).join('-')
dataObj.grouped = array[1]
result.push( dataObj )
console.log( result )
return result
}

Mege multiple array object into single array object based on key

I have an array of objects of the structure coming from server response of iterated array object like as sample
var arrObj1 = [
{"id":"1","value":21, "value1":13},
{"id":"2","value":21, "value1":13 },
......n
];
var arrObj2 = [
{"id":"1","value3":21, "value14":13},
{"id":"2","value3":21, "value4":13 },
......n
];
var arrObj3 = [
{"id":"1","value5":21, "value6":13},
{"id":"2","value5":21, "value6":13 },
......n
];
But now I want to append the array values inot single new array according to key following structure of as iterated values of above array Expected Output:
var finalObj = [
{
"id" : 1
"value" : 21,
"value1" : 13,
"value3" : 21,
"value4" : 13,
"value5" : 21,
"value6" : 13,
},
{
"id" : 2
"value" : 21,
"value1" : 13,
"value3" : 21,
"value4" : 13,
"value5" : 21,
"value6" : 13,
},
.....n
];
You can use reduce for concated arrays
const arrObj1 = [
{ id: '1', value: 21, value1: 13 },
{ id: '2', value: 21, value1: 13 },
];
const arrObj2 = [
{ id: '1', value3: 21, value14: 13 },
{ id: '2', value3: 21, value4: 13 },
];
const arrObj3 = [
{ id: '1', value5: 21, value6: 13 },
{ id: '2', value5: 21, value6: 13 },
];
const result = [...arrObj1, ...arrObj2, ...arrObj3].reduce(
(acc, { id, ...rest }) => ({ ...acc, [id]: acc[id] ? { ...acc[id], ...rest } : { ...rest } }),
{},
);
console.log(Object.entries(result).map(([id, data]) => ({ id, ...data })));
Push you arrays to a new array (you have to have your sub arrays in other list to loop through them) and then use flat, after that group your object according to the id property
var arrObj1 = [{
"id": "1",
"value": 21,
"value1": 13
},
{
"id": "2",
"value": 21,
"value1": 13
},
];
var arrObj2 = [{
"id": "1",
"value3": 21,
"value14": 13
},
{
"id": "2",
"value3": 21,
"value4": 13
},
];
var arrObj3 = [{
"id": "1",
"value5": 21,
"value6": 13
},
{
"id": "2",
"value5": 21,
"value6": 13
},
];
const input = [];
input.push(arrObj2, arrObj3);
const preResult = input.flat();
result = preResult.reduce((acc, x) => {
const index = acc.findIndex(y => y.id === x.id)
if (index >= 0) {
acc[index] = {
...acc[index],
...x
}
} else {
acc.push(x)
}
return acc;
}, arrObj1)
console.log(result)
You can iterate over array-length and push here for every entry 1 entry to the result. For getting this entry take a new object with the id and iterate over all (3 or perhaps more) arrays. For every array take the i-th entry and push for every key an entry with key:value (except for the key id itself).
Remark: You can use as much arrays you want and every object could contain as much value-prperties as you need. The only restriction is that every array has the same count of objects.
var arrObj1 = [
{"id":"1","value":21, "value1":13},
{"id":"2","value":21, "value1":13 }
];
var arrObj2 = [
{"id":"1","value3":21, "value4":13},
{"id":"2","value3":21, "value4":13 }
];
var arrObj3 = [
{"id":"1","value5":21, "value6":13},
{"id":"2","value5":21, "value6":13 }
];
let result =[];
let arrayAll = [arrObj1, arrObj2, arrObj3];
for (let i=0; i<arrayAll[0].length; i++) {
let obj = arrayAll[0][i];
let res = { id: obj.id};
for (let j=0; j<arrayAll.length; j++) {
let obj = arrayAll[j][i];
Object.keys(obj).forEach(key => {
if (key!='id') res[key] = obj[key];
})
}
result.push(res);
}
console.log(result);
Since you are using id to merge multiple objects, Map is one of the good option to merge.
let arrObj1 = [
{"id":"1","value":21, "value1":13},
{"id":"2","value":21, "value1":13 },
];
let arrObj2 = [
{"id":"1","value3":21, "value14":13},
{"id":"2","value3":21, "value4":13 },
];
let arrObj3 = [
{"id":"1","value5":21, "value6":13},
{"id":"2","value5":21, "value6":13 },
];
let mergedArray = [...arrObj1,...arrObj2,...arrObj3].reduce((acc,curr) =>{
if(acc.has(curr.id)){
acc.set(curr.id, {...acc.get(curr.id),...curr});
}else{
acc.set(curr.id,curr);
}
return acc;
},new Map())
console.log(Array.from(mergedArray,x=>x[1]));

Rearranging array based on time values [duplicate]

I am trying to sort the time. but I am unable to sort by time (hh:mm:ss) format. so i have used moments js. my array sort by time not get sorted. how sort array by using maps
I have an array of objects:
let elements =[
{
"id": 1,
"date": "02:01:02"
},
{
"id": 2,
"date": "01:01:01"
},
{
"id": 3,
"date": "03:01:01"
},
{
"id": 4,
"date": "04:01:01"
}
];
let parsedDates = new Map(
elements.map(e =>[["id", "date"],[e.id, moment(e.date, 'hh:mm:ss')]])
);
elements.sort((a, b) => parsedDates.get(a) - parsedDates.get(b));
console.log(elements.map(e => ({ id: e.id, date: e.date })));
You can lexicographical sort the time using string.localeCompare().
let times = [ { "id": 1, "date": "02:01:02" }, { "id": 2, "date": "01:01:01" }, { "id": 3, "date": "03:01:01" }, { "id": 4, "date": "04:01:01" } ];
times.sort((a,b) => a.date.localeCompare(b.date));
console.log(times);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You can try this
function convertDateObj(hhmmss){
let obj = new Date();//creates a Date Object using the clients current time
let [hours,minutes,seconds] = hhmmss.split(':');
obj.setHours(+hours); // set the hours, using implicit type coercion
obj.setMinutes(minutes); //you can pass Number or String, it doesn't really matter
obj.setSeconds(seconds);
return obj;
}
let elements =[
{
"id": 1,
"date": "02:01:02"
},
{
"id": 2,
"date": "01:01:01"
},
{
"id": 3,
"date": "03:01:01"
},
{
"id": 4,
"date": "04:01:01"
}
];
elements.sort((a, b) => convertDateObj(a.date) - convertDateObj(b.date)); // Ascending order
elements.sort((a, b) => convertDateObj(b.date) - convertDateObj(a.date)); // Descending order
The parsedDates map you've created is looking like:
Map {
[ 'id', 'date' ] => [ 1, <some Date object> ],
[ 'id', 'date' ] => [ 2, <some Date object> ],
[ 'id', 'date' ] => [ 3, <some Date object> ],
[ 'id', 'date' ] => [ 4, <some Date object> ]
}
And then you try to extract from it with elements like this:
parsedDates.get({ "id": 1, "date": "02:01:02" })
This should not work, because the key in a Map is and Array instance.
Even if you were using an array as a key:
parsedDates.get([ 1, "02:01:02" ])
this still wouldn't work, as this would be a different Object reference. I mean two arrays
a = [ 1, "02:01:02" ]
b = [ 1, "02:01:02" ]
are stored in different places and are different Objects, even though their values are identical.
So, you can modify your solution a bit:
let elements =[
{
"id": 1,
"date": "02:01:02"
},
{
"id": 2,
"date": "01:01:01"
},
{
"id": 3,
"date": "03:01:01"
},
{
"id": 4,
"date": "04:01:01"
}
];
let parsedDates = new Map(
elements.map(e => [e.date, e])
);
elements = elements.map(x => x.date).sort().map(x => parsedDates.get(x))
console.log(elements)
// [
// { id: 2, date: '01:01:01' },
// { id: 1, date: '02:01:02' },
// { id: 3, date: '03:01:01' },
// { id: 4, date: '04:01:01' }
// ]

sorting array object based on other array

i am creating a table based on the list tablelist given,where i am creating my table header from tablefield,but i want my header to be ordered according to tableordering property
var tablelist = {
"member": {
"name": "Richie",
"id": 5
},
"submission_time": "10/03/2018 00:00:00",
"tablefield": [
{
"field_name": "top1",
"value": 1,
},
{
"field_name": "top5",
"value": 5,
},
{
"field_name": "top3",
"value": 3,
},
{
"field_name": "top2",
"value": 2,
},
{
"field_name": "top4",
"value": 4,
},
],
"tableordering": [
"member",
"top1",
"top2",
"top3",
"top4",
"top5",
"submission_time",
]
}
i want my list result to be like
var result = [{member:"Richie",top1:"1",top2:"1",top3:"1",top4:"1",top5:"1",submission-time:"1"}]
below is the code
var lists = tablelist.reduce((acc, cur) => {
acc[cur.field_name] = cur.value;
return acc;
}, {});
var listres = Object.assign({}, lists, {
member: i.member.name,
submission_time: i.submission_time
});
but then sorting with tableordering, i do not know,could someone help
🏴󠁡󠁦󠁷󠁡󠁲󠁿 Divide and rule or reduce and map:
const tablelist = {
member: {name: `Richie`, id: 5},
submission_time: `10/03/2018 00:00:00`,
tablefield: [
{field_name: `top1`, value: 1},
{field_name: `top5`, value: 5},
{field_name: `top3`, value: 3},
{field_name: `top2`, value: 2},
{field_name: `top4`, value: 4}
],
tableordering: [
`member`,
`top1`,
`top2`,
`top3`,
`top4`,
`top5`,
`submission_time`
]
}
const {member: {name: member}, submission_time} = tablelist
const fields = tablelist.tablefield.reduce((list, {field_name, value}) => {
list[field_name] = value
return list
}, {})
const data = {member, submission_time, ...fields}
const result = [tablelist.tableordering.reduce((list, key) => {
list[key]= data[key]
return list
}, {})]
console.log(result)

Merge two array of objects based on a key

I have two arrays:
Array 1:
[
{ id: "abdc4051", date: "2017-01-24" },
{ id: "abdc4052", date: "2017-01-22" }
]
and array 2:
[
{ id: "abdc4051", name: "ab" },
{ id: "abdc4052", name: "abc" }
]
I need to merge these two arrays based on id and get this:
[
{ id: "abdc4051", date: "2017-01-24", name: "ab" },
{ id: "abdc4052", date: "2017-01-22", name: "abc" }
]
How can I do this without iterating trough Object.keys?
You can do it like this -
let arr1 = [
{ id: "abdc4051", date: "2017-01-24" },
{ id: "abdc4052", date: "2017-01-22" }
];
let arr2 = [
{ id: "abdc4051", name: "ab" },
{ id: "abdc4052", name: "abc" }
];
let arr3 = arr1.map((item, i) => Object.assign({}, item, arr2[i]));
console.log(arr3);
Use below code if arr1 and arr2 are in a different order:
let arr1 = [
{ id: "abdc4051", date: "2017-01-24" },
{ id: "abdc4052", date: "2017-01-22" }
];
let arr2 = [
{ id: "abdc4051", name: "ab" },
{ id: "abdc4052", name: "abc" }
];
let merged = [];
for(let i=0; i<arr1.length; i++) {
merged.push({
...arr1[i],
...(arr2.find((itmInner) => itmInner.id === arr1[i].id))}
);
}
console.log(merged);
Use this if arr1 and arr2 are in a same order
let arr1 = [
{ id: "abdc4051", date: "2017-01-24" },
{ id: "abdc4052", date: "2017-01-22" }
];
let arr2 = [
{ id: "abdc4051", name: "ab" },
{ id: "abdc4052", name: "abc" }
];
let merged = [];
for(let i=0; i<arr1.length; i++) {
merged.push({
...arr1[i],
...arr2[i]
});
}
console.log(merged);
You can do this in one line
let arr1 = [
{ id: "abdc4051", date: "2017-01-24" },
{ id: "abdc4052", date: "2017-01-22" }
];
let arr2 = [
{ id: "abdc4051", name: "ab" },
{ id: "abdc4052", name: "abc" }
];
const mergeById = (a1, a2) =>
a1.map(itm => ({
...a2.find((item) => (item.id === itm.id) && item),
...itm
}));
console.log(mergeById(arr1, arr2));
Map over array1
Search through array2 for array1.id
If you find it ...spread the result of array2 into array1
The final array will only contain id's that match from both arrays
This solution is applicable even when the merged arrays have different sizes.
Also, even if the matching keys have different names.
Merge the two arrays by using a Map as follows:
const arr1 = [
{ id: "abdc4051", date: "2017-01-24" },
{ id: "abdc4052", date: "2017-01-22" },
{ id: "abdc4053", date: "2017-01-22" }
];
const arr2 = [
{ nameId: "abdc4051", name: "ab" },
{ nameId: "abdc4052", name: "abc" }
];
const map = new Map();
arr1.forEach(item => map.set(item.id, item));
arr2.forEach(item => map.set(item.nameId, {...map.get(item.nameId), ...item}));
const mergedArr = Array.from(map.values());
console.log(JSON.stringify(mergedArr));
.as-console-wrapper { max-height: 100% !important; top: 0; }
Run the stack snippet to see the result:
[
{
"id": "abdc4051",
"date": "2017-01-24",
"nameId": "abdc4051",
"name": "ab"
},
{
"id": "abdc4052",
"date": "2017-01-22",
"nameId": "abdc4052",
"name": "abc"
},
{
"id": "abdc4053",
"date": "2017-01-22"
}
]
Here's an O(n) solution using reduce and Object.assign
const joinById = ( ...lists ) =>
Object.values(
lists.reduce(
( idx, list ) => {
list.forEach( ( record ) => {
if( idx[ record.id ] )
idx[ record.id ] = Object.assign( idx[ record.id ], record)
else
idx[ record.id ] = record
} )
return idx
},
{}
)
)
To use this function for the OP's case, pass in the arrays you want to join to joinById (notice lists is a rest parameter).
let joined = joinById(list1, list2)
Each list gets reduced to a single object where the keys are ids and the values are the objects. If there's a value at the given key already, it gets object.assign called on it and the current record.
Here's the generic O(n*m) solution, where n is the number of records and m is the number of keys. This will only work for valid object keys. You can convert any value to base64 and use that if you need to.
const join = ( keys, ...lists ) =>
lists.reduce(
( res, list ) => {
list.forEach( ( record ) => {
let hasNode = keys.reduce(
( idx, key ) => idx && idx[ record[ key ] ],
res[ 0 ].tree
)
if( hasNode ) {
const i = hasNode.i
Object.assign( res[ i ].value, record )
res[ i ].found++
} else {
let node = keys.reduce( ( idx, key ) => {
if( idx[ record[ key ] ] )
return idx[ record[ key ] ]
else
idx[ record[ key ] ] = {}
return idx[ record[ key ] ]
}, res[ 0 ].tree )
node.i = res[ 0 ].i++
res[ node.i ] = {
found: 1,
value: record
}
}
} )
return res
},
[ { i: 1, tree: {} } ]
)
.slice( 1 )
.filter( node => node.found === lists.length )
.map( n => n.value )
This is essentially the same as the joinById method, except that it keeps an index object to identify records to join. The records are stored in an array and the index stores the position of the record for the given key set and the number of lists it's been found in.
Each time the same key set is encountered, it finds the node in the tree, updates the element at it's index, and the number of times it's been found is incremented.
After joining, the idx object is removed from the array with the slice and any elements that weren't found in each set are removed. This makes it an inner join, you could remove this filter and have a full outer join.
Finally each element is mapped to it's value, and you have the joined arrays.
You could use an arbitrary count of arrays and map on the same index new objects.
var array1 = [{ id: "abdc4051", date: "2017-01-24" }, { id: "abdc4052", date: "2017-01-22" }],
array2 = [{ id: "abdc4051", name: "ab" }, { id: "abdc4052", name: "abc" }],
result = [array1, array2].reduce((a, b) => a.map((c, i) => Object.assign({}, c, b[i])));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
If you have 2 arrays need to be merged based on values even its in different order
let arr1 = [
{ id:"1", value:"this", other: "that" },
{ id:"2", value:"this", other: "that" }
];
let arr2 = [
{ id:"2", key:"val2"},
{ id:"1", key:"val1"}
];
you can do like this
const result = arr1.map(item => {
const obj = arr2.find(o => o.id === item.id);
return { ...item, ...obj };
});
console.log(result);
To merge the two arrays on id, assuming the arrays are equal length:
arr1.map(item => ({
...item,
...arr2.find(({ id }) => id === item.id),
}));
We can use lodash here. _.merge works as you expected. It works with the common key present.
_.merge(array1, array2)
Non of these solutions worked for my case:
missing objects can exist in either array
runtime complexity of O(n)
notes:
I used lodash but it's easy to replace with something else
Also used Typescript (just remove/ignore the types)
import { keyBy, values } from 'lodash';
interface IStringTMap<T> {
[key: string]: T;
}
type IIdentified = {
id?: string | number;
};
export function mergeArrayById<T extends IIdentified>(
array1: T[],
array2: T[]
): T[] {
const mergedObjectMap: IStringTMap<T> = keyBy(array1, 'id');
const finalArray: T[] = [];
for (const object of array2) {
if (object.id && mergedObjectMap[object.id]) {
mergedObjectMap[object.id] = {
...mergedObjectMap[object.id],
...object,
};
} else {
finalArray.push(object);
}
}
values(mergedObjectMap).forEach(object => {
finalArray.push(object);
});
return finalArray;
}
You can use array methods
let arrayA=[
{id: "abdc4051", date: "2017-01-24"},
{id: "abdc4052", date: "2017-01-22"}]
let arrayB=[
{id: "abdc4051", name: "ab"},
{id: "abdc4052", name: "abc"}]
let arrayC = [];
arrayA.forEach(function(element){
arrayC.push({
id:element.id,
date:element.date,
name:(arrayB.find(e=>e.id===element.id)).name
});
});
console.log(arrayC);
//0:{id: "abdc4051", date: "2017-01-24", name: "ab"}
//1:{id: "abdc4052", date: "2017-01-22", name: "abc"}
Here is one-liner (order of elements in array is not important and assuming there is 1 to 1 relationship):
var newArray = array1.map(x=>Object.assign(x, array2.find(y=>y.id==x.id)))
I iterated through the first array and used the .find method on the second array to find a match where the id are equal and returned the result.
const a = [{ id: "abdc4051", date: "2017-01-24" },{ id: "abdc4052", date: "2017-01-22" }];
const b = [{ id: "abdc4051", name: "ab" },{ id: "abdc4052", name: "abc" }];
console.log(a.map(itm => ({...itm, ...b.find(elm => elm.id == itm.id)})));
You can recursively merge them into one as follows:
function mergeRecursive(obj1, obj2) {
for (var p in obj2) {
try {
// Property in destination object set; update its value.
if (obj2[p].constructor == Object) {
obj1[p] = this.mergeRecursive(obj1[p], obj2[p]);
} else {
obj1[p] = obj2[p];
}
} catch (e) {
obj1[p] = obj2[p];
}
}
return obj1;
}
arr1 = [
{ id: "abdc4051", date: "2017-01-24" },
{ id: "abdc4052", date: "2017-01-22" }
];
arr2 = [
{ id: "abdc4051", name: "ab" },
{ id: "abdc4052", name: "abc" }
];
mergeRecursive(arr1, arr2)
console.log(JSON.stringify(arr1))
Irrespective of the order you can merge it by,
function merge(array,key){
let map = {};
array.forEach(val=>{
if(map[val[key]]){
map[val[key]] = {...map[val[key]],...val};
}else{
map[val[key]] = val;
}
})
return Object.keys(map).map(val=>map[val]);
}
let b = [
{ id: "abdc4051", name: "ab" },
{ id: "abdc4052", name: "abc" }
];
let a = [
{ id: "abdc4051", date: "2017-01-24" },
{ id: "abdc4052", date: "2017-01-22" }
];
console.log(merge( [...a,...b], 'id'));
An approach if both two arrays have non-intersect items.
const firstArray = [
{ id: 1, name: "Alex", salutation: "Mr." },
{ id: 2, name: "Maria", salutation: "Ms." },
];
const secondArray = [
{ id: 2, address: "Larch Retreat 31", postcode: "123452" },
{ id: 3, address: "Lycroft Close 12D", postcode: "123009" },
];
const mergeArr = (arr1, arr2) => {
const obj = {};
arr1.forEach(item => {
obj[item.id] = item;
});
arr2.forEach(item => {
obj[item.id]
? (obj[item.id] = { ...obj[item.id], ...item })
: (obj[item.id] = item);
});
return Object.values(obj);
};
const output = mergeArr(firstArray, secondArray);
console.log(output);
Python 3 Solution for someone who lands on this page in hope of finding one
def merge(studentDetails, studentMark, merge_key):
student_details = {}
student_marks = {}
for sd, sm in zip(studentDetails, studentMark):
key = sd.pop(merge_key)
student_details[key] = sd
key = sm.pop(merge_key)
student_marks[key] = sm
res = []
for id, val in student_details.items():
# Merge three dictionary together
temp = {**{"studentId": id}, **val, **student_marks[id]}
res.append(temp)
return res
if __name__ == '__main__':
# Test Case 1
studentDetails = [
{"studentId": 1, "studentName": 'Sathish', "gender": 'Male', "age": 15},
{"studentId": 2, "studentName": 'kumar', "gender": 'Male', "age": 16},
{"studentId": 3, "studentName": 'Roja', "gender": 'Female', "age": 15},
{"studentId": 4, "studentName": 'Nayanthara', "gender": 'Female', "age": 16},
]
studentMark = [
{"studentId": 1, "mark1": 80, "mark2": 90, "mark3": 100},
{"studentId": 2, "mark1": 80, "mark2": 90, "mark3": 100},
{"studentId": 3, "mark1": 80, "mark2": 90, "mark3": 100},
{"studentId": 4, "mark1": 80, "mark2": 90, "mark3": 100},
]
# Test Case 2
array1 = [
{"id": "abdc4051", "date": "2017-01-24"},
{"id": "abdc4052", "date": "2017-01-22"}
]
array2 = [
{"id": "abdc4051", "name": "ab"},
{"id": "abdc4052", "name": "abc"}
]
output = merge(studentDetails, studentMark, merge_key="studentId")
[print(a) for a in output]
output = merge(array1, array2, merge_key="id")
[print(a) for a in output]
Output
{'studentId': 1, 'studentName': 'Sathish', 'gender': 'Male', 'age': 15, 'mark1': 80, 'mark2': 90, 'mark3': 100}
{'studentId': 2, 'studentName': 'kumar', 'gender': 'Male', 'age': 16, 'mark1': 80, 'mark2': 90, 'mark3': 100}
{'studentId': 3, 'studentName': 'Roja', 'gender': 'Female', 'age': 15, 'mark1': 80, 'mark2': 90, 'mark3': 100}
{'studentId': 4, 'studentName': 'Nayanthara', 'gender': 'Female', 'age': 16, 'mark1': 80, 'mark2': 90, 'mark3': 100}
{'studentId': 'abdc4051', 'date': '2017-01-24', 'name': 'ab'}
{'studentId': 'abdc4052', 'date': '2017-01-22', 'name': 'abc'}
Well... assuming both arrays are of the same length, I would probably do something like this:
var newArr = []
for (var i = 0; i < array1.length; i++ {
if (array1[i].id === array2[i].id) {
newArr.push({id: array1[i].id, date: array1[i].date, name: array2[i].name});
}
}
I was able to achieve this with a nested mapping of the two arrays and updating the initial array:
member.map(mem => {
return memberInfo.map(info => {
if (info.id === mem.userId) {
mem.date = info.date;
return mem;
}
}
}
There are a lot of solutions available for this, But, We can simply use for loop and if conditions to get merged arrays.
const firstArray = [
{ id: 1, name: "Alex", salutation: "Mr." },
{ id: 2, name: "Maria", salutation: "Ms." },
];
const secondArray = [
{ id: 1, address: "Larch Retreat 31", postcode: "123452" },
{ id: 2, address: "Lycroft Close 12D", postcode: "123009" },
];
let mergedArray: any = [];
for (const arr1 of firstArray) {
for (arr2 doc of secondArray) {
if (arr1.id === arr2.id) {
mergedArray.push({ ...arr1, ...arr2 });
}
}
}
console.log(mergedArray)
Here is converting the best answer (jsbisht) into a function that accepts the keys as arguments.
const mergeArraysByKeyMatch = (array1, array2, key1, key2) => {
const map = new Map();
array1.forEach((item) => map.set(item[key1], item));
array2.forEach((item) =>
map.set(item[key2], { ...map.get(item[key2]), ...item })
);
const merged = Array.from(map.values());
return merged;
};
A Typescript O(n+m) (which could be classified as O(n)) solution; without lodash:
// RequireAtLeastOne from https://stackoverflow.com/questions/40510611/typescript-interface-require-one-of-two-properties-to-exist/49725198#49725198
type RequireAtLeastOne<T, Keys extends keyof T = keyof T> = Pick<
T,
Exclude<keyof T, Keys>
> &
{
[K in Keys]-?: Required<Pick<T, K>> & Partial<Pick<T, Exclude<Keys, K>>>;
}[Keys];
export const mergeDualArraysOnKey = <
K extends PropertyKey,
T extends RequireAtLeastOne<{ [f in PropertyKey]?: unknown }, K>
>(
key: K,
...lists: [T[], T[]]
): T[] => {
const lookup: { [key in string]: number } = {};
return lists[0].concat(lists[1]).reduce((acc: T[], value: T, i: number) => {
const lookupKey = `${value[key]}`;
if (lookup.hasOwnProperty(lookupKey)) {
acc[lookup[lookupKey]] = Object.assign({}, acc[lookup[lookupKey]], value);
} else {
acc.push(value);
lookup[lookupKey] = acc.length - 1;
}
return acc;
}, []);
};
First concatenates the two arrays and then iterates through the newly created array. It uses a lookup table (object) to store the index of an item in the final merged array which has the same key and merges the objects inplace.
If this needed to be extended to handle more arrays, could use a loop or recursion as a wrapping function:
const mergeArrays = <
K extends PropertyKey,
T extends RequireAtLeastOne<{ [f in PropertyKey]?: unknown }, K>
>(
key: K,
...lists: T[][]
): T[] => {
if (lists.length === 1) {
return lists[0];
}
const l1 = lists.pop() || [];
const l2 = lists.pop() || [];
return mergeArrays(key, mergeDualArraysOnKey(key, l1, l2), ...lists);
};
with usage being:
const arr1 = [
{ id: "abdc4052", date: "2017-01-22" },
{ id: "abdc4052", location: "US" },
{ id: "abdc4051", date: "2017-01-24" },
{ id: "abdc4053", date: "2017-01-24" },
{ id: "abdc4054", date: "2017-01-24" },
{ id: "abdc4055", location: "US" },
];
const arr2 = [
{ id: "abdc4052", date: "2017-01-22" },
{ id: "abdc4052", name: "abc" },
{ id: "abdc4055", date: "2017-01-24" },
{ id: "abdc4055", date: "2017-01-24", name: "abcd" },
];
const arr3 = [{ id: "abdc4056", location: "US" }];
const arr4 = [
{ id: "abdc4056", name: "abcde" },
{ id: "abdc4051", name: "ab--ab" },
];
mergeArrays<
"id",
{
id: string;
date?: string;
location?: string;
name?: string;
}
>("id", arr1, arr2, arr3, arr4)
Base on your example, you can do it this way:
const arrayOne = [
{ id: "abdc4051", date: "2017-01-24" },
{ id: "abdc4052", date: "2017-01-22" }
]
const arrayTwo = [
{ id: "abdc4051", name: "ab" },
{ id: "abdc4052", name: "abc" }
]
const mergeArrays = () => {
arrayOne.forEach((item, i) => {
const matchedFound = arrayTwo.findIndex(a => a.id === item.id);
arrayOne[i] = {
...item,
...matchedFound,
}
});
};
mergeArrays();
console.log(arrayOne);
This is a version when you have an object and an array and you want to merge them and give the array a key value so it fits into the object nicely.
var fileData = [
{ "id" : "1", "filename" : "myfile1", "score" : 33.1 },
{ "id" : "2", "filename" : "myfile2", "score" : 31.4 },
{ "id" : "3", "filename" : "myfile3", "score" : 36.3 },
{ "id" : "4", "filename" : "myfile4", "score" : 23.9 }
];
var fileQuality = [0.23456543,0.13413131,0.1941344,0.7854522];
var newOjbect = fileData.map((item, i) => Object.assign({}, item, {fileQuality:fileQuality[i]}));
console.log(newOjbect);

Categories