I have an array of arrays, of the same size, of objects like this:
const array = [
[{ name: 'John' }, { name: 'Julie' }, { name: 'Zack' }],
[{ color: 'blue' }, { color: 'orange' }, { color: 'green' }],
[{ age: 12 }, { age: 10 }, { age: 35 }]
];
How do I merge these arrays object by object to have an output like this?
const result = [{ name: 'John', color: 'blue', age: 12 }, { name: 'Julie', color: 'orange', age: 10 } ...]
If it could be using lodash, it would be nice too. Thanks in advance
You can use map and destructuring
const array1 = [{ name: 'John' }, { name: 'Julie' }, { name: 'Zack' }];
const array2 = [{ color: 'blue' }, { color: 'orange' }, { color: 'green' }];
const array3 = [{ age: 12 }, { age: 10 }, { age: 35 }];
let final = array1.map((a, i) => ({ ...a,
...array2[i],
...array3[i]
}))
console.log(final)
But would it work with several arrays?
const array = [
[{ name: 'John' }, { name: 'Julie' }, { name: 'Zack' }],
[{ color: 'blue' }, { color: 'orange' }, { color: 'green' }],
[{ age: 12 }, { age: 10 }, { age: 35 }],
[{ someProp: 1 }, { someProp: 2 }, { someProp: 3 }]
];
let remaining = array.slice(1,)
let final = array[0].map((v,i)=>{
let temp = {...v}
remaining.forEach(v2=>{
temp = {...temp, ...v2[i]}
})
return temp
})
console.log(final)
A caveman approach - pushing to an array from a for-loop.
const array1 = [{ name: 'John' }, { name: 'Julie' }, { name: 'Zack' }];
const array2 = [{ color: 'blue' }, { color: 'orange' }, { color: 'green' }];
const array3 = [{ age: 12 }, { age: 10 }, { age: 35 }];
let result = [];
for ( let i = 0; i < array1.length; i++ ){
result.push( { ...array1[i], ...array2[i], ...array3[i] } );
}
console.log( result );
const result = array1.map((el, index) => ({
...el,
...array2[index],
...array3[index]
}))
you don't need lodash, its easy enough with vanilla JS using array.map.
I'm assuming you have same number of object in all 3 arrays, if you need to also handle the case that there aren't- let me know.
array1.map( (el, index) =>
({ ...el, ...array2[index], ...array3[index] })
);
For a variable amount of arrays aka 2 dimensional array:
const array1 = [{ name: 'John' }, { name: 'Julie' }, { name: 'Zack' }];
const array2 = [{ color: 'blue' }, { color: 'orange' }, { color: 'green' }];
const array3 = [{ age: 12 }, { age: 10 }, { age: 35 }];
const array4 = [{ foo: 'bar'}, {foo: 'baz'}];
const mergeFirst = (arrays) => {
return [...arrays.map(arr => arr[0])].reduce((obj, val) => ({
...obj,
...val,
}), {});
}
const mergeAttributes = (arrays, results = []) => {
return (arrays[0].length) ? mergeAttributes(arrays.map(arr => arr.slice(1, arr.length)), results.concat(mergeFirst(arrays))) : results;
}
console.log( mergeAttributes([array1,array2,array3,array4]) );
Related
I cant figure out how to do this...
const arr1 = [{ name: 'peter' }, { name: 'sam', id: 1 }, { name: 'mark' }];
const arr2 = [{ name: 'sam' }, { name: 't' }, { name: 'george' }];
Desired outcome:
const arr2 = [{ name: 'sam', id: 1 }, { name: 't' }, { name: 'george' }];
If you want the previous item I would do this:
const arr1 = [{
name: 'peter'
}, {
name: 'sam',
id: 1
}, {
name: 'mark'
}];
const arr2 = [{
name: 'sam'
}, {
name: 't'
}, {
name: 'george'
}];
const result = arr2.map(item => {
const previousItem = arr1.find(i => i.name === item.name)
if (previousItem) {
return previousItem
}
return item
})
console.log(result);
However, if you want to combine the old and new data, I would recommend spreading the data together, like so:
const arr1 = [{
name: 'peter'
}, {
name: 'sam',
id: 1
}, {
name: 'mark'
}];
const arr2 = [{
name: 'sam'
}, {
name: 't'
}, {
name: 'george'
}];
const result = arr2.map(item => {
const previousItem = arr1.find(i => i.name === item.name)
if (previousItem) {
return {
...previousItem,
...item
}
}
return item
})
console.log(result);
Both allude to the same result here, but you would get different results if arr2's "Sam" object had an additional key "age" on it...
In this example, the second snippet would keep the "age" key because the spread (...) operation combines the two objects together.
You can try this.
const arr1 = [{ name: 'peter' }, { name: 'sam', id: 1 }, { name: 'mark' }];
const arr2 = [{ name: 'sam' }, { name: 't' }, { name: 'george' }];
const result = [];
const res1 = arr2.map((item, i) => {
let index = arr1.findIndex((x) => x.name === item.name);
if ( index > -1 )
result.push(arr1[index]);
else
result.push(item);
})
console.log(result);
I have two objects array:
let arr1 = [
{ id: "abdc4051", color: "red" },
{ id: "abdc4052", color: "blue" }
];
let arr2 = [
{ uid: "abdc4051", name: "wall" },
{ uid: "abdc4052", name: "kitchen" },
{ uid: "abdc4053", name: "sofa" },
{ uid: "abdc4054", name: "room" }
];
I need to make join by id and uid, according to example above I expect this result:
let arrNew = [
{ uid: "abdc4051", name: "wall", color: "red" },
{ uid: "abdc4052", name: "kitchen", color: "blue" }
];
I what the elegant way to do it in ES6?
You can approach this way to get the highest performance.
As a result, the Big O (time complexity) just take max(O(N) of arr1, O(N) of arr2)
let arr1 = [{ id: "abdc4051", color: "red" },
{ id: "abdc4052", color: "blue" }];
let arr2 = [{ uid: "abdc4051", name: "wall" },
{ uid: "abdc4052", name: "kitchen" },
{ uid: "abdc4053", name: "sofa" },
{ uid: "abdc4054", name: "room" }];
let result = [], countIndex_1 = 0, countIndex_2 = 0;
while(countIndex_1 < arr1.length && countIndex_2 < arr2.length){
var item1 = arr1[countIndex_1], item2 = arr2[countIndex_2];
if(item1.id == item2.uid){
result.push({uid: item2.uid, name: item2.name, color: item1.color});
countIndex_1 ++, countIndex_2 ++;
}else if(item1.id < item2.uid)
countIndex_1 ++;
else
countIndex_2 ++;
}
console.log(result);
Note: Assuming that your 2 arrays are sorted, otherwise, you should
sort them first.
arr1.sort((a, b) => a.id - b.id);
arr2.sort((a, b) => a.uid - b.uid);
I am fairly certain this does not qualify as elegant, but this is how I would do it.
const arr1 = [
{ id: "abdc4051", color: "red" },
{ id: "abdc4052", color: "blue" }
];
const arr2 = [
{ uid: "abdc4051", name: "wall" },
{ uid: "abdc4052", name: "kitchen" },
{ uid: "abdc4053", name: "sofa" },
{ uid: "abdc4054", name: "room" }
];
let arr3=[]
arr1.forEach(a1 => {
arr2.forEach(a2 => {
if (a1.id === a2.uid) {
arr3.push({ uid: a1.id, color: a1.color, name: a2.name})
}
})
})
console.log(arr3)
let arr1 = [
{ id: "abdc4051", color: "red" },
{ id: "abdc4052", color: "blue" }
];
let arr2 = [
{ uid: "abdc4051", name: "wall" },
{ uid: "abdc4052", name: "kitchen" },
{ uid: "abdc4053", name: "sofa" },
{ uid: "abdc4054", name: "room" }
];
let result = arr2.map(eachInArr2 => {
const matchedElementInArr1 = arr1.filter(eachInArr1 => eachInArr1.id === eachInArr2.uid);
if (matchedElementInArr1.length === 0) {
return null;
}
const merged = {
...matchedElementInArr1[0],
...eachInArr2,
};
delete merged['id'];
return merged;
}).filter(each => each);
console.log(result);
Maybe this way ?
const
arr1 =
[ { id: 'abdc4051', color: 'red' }
, { id: 'abdc4052', color: 'blue' }
]
, arr2 =
[ { uid: 'abdc4051', name: 'wall' }
, { uid: 'abdc4052', name: 'kitchen' }
, { uid: 'abdc4053', name: 'sofa' }
, { uid: 'abdc4054', name: 'room' }
]
, result = arr1.reduce((a,{id,...a1N})=>
{
let {uid,...a2N} = arr2.find(x=>x.uid===id) || {uid:null}
if(uid)
a.push({ uid,...a2N,...a1N })
return a
},[])
console.log( result )
.as-console-wrapper { max-height: 100% !important; top: 0; }
let arr1 = [
{ id: "abdc4051", color: "red" },
{ id: "abdc4052", color: "blue" }
];
let arr2 = [
{ uid: "abdc4051", name: "wall" },
{ uid: "abdc4052", name: "kitchen" },
{ uid: "abdc4053", name: "sofa" },
{ uid: "abdc4054", name: "room" }
];
let arr3 = [];
arr1.map( item1 => {
arr3 = arr3.concat( arr2.filter( item => item1.id === item.uid ) );
arr3.map( item => item1.id === item.uid ? item.color = item1.color : '' );
} );
console.log(arr3);
You could use Map Object.
const arr1 = [
{ id: 'abdc4051', color: 'red' },
{ id: 'abdc4052', color: 'blue' },
];
const arr2 = [
{ uid: 'abdc4051', name: 'wall' },
{ uid: 'abdc4052', name: 'kitchen' },
{ uid: 'abdc4053', name: 'sofa' },
{ uid: 'abdc4054', name: 'room' },
];
const ret = [];
const map = new Map();
arr1.forEach(({ id, color }) => map.set(id, { color }));
arr2.forEach(
({ uid, name }) => map.has(uid) && ret.push({ uid, name, ...map.get(uid) })
);
console.log(ret);
I have two arrays of objects
const a = [
{ name: 'apple', type: 'fruit' },
{ name: 'berry', type: 'fruit' },
{ name: 'grape', type: 'fruit' },
{ name: 'broccoli', type: 'vegetable' },
{ name: 'cabbage', type: 'vegetable' },
]
const b = [
{ name: 'apple', amount: 4 },
{ name: 'berry', amount: 5 },
{ name: 'grape', amount: 3 },
{ name: 'broccoli', amount: 7 },
{ name: 'avocado', amount: 8 },
]
I need to write a function to output an array with objects with the same name being merged into one.
const c = [
{ name: 'apple', type: 'fruit', amount: 4 },
{ name: 'berry', type: 'fruit', amount: 5 },
{ name: 'grape', type: 'fruit', amount: 3 },
{ name: 'broccoli', type: 'vegetable', amount: 7 },
{ name: 'cabbage', type: 'vegetable', amount: 0 },
{ name: 'avocado', type: undefined, amount: 8 },
]
As you can see here, objects that share the same name are merged into one object with a few exceptions:
if type field is missing, we would need to add it and make it undefined
if amount field is missing, we need to add it and make it 0
Here is my attempt:
function fillMissingFields(object) {
console.log('object', object)
let newObject = { ...object }
if (object.type === undefined) {
newObject = { ...object, type: undefined }
}
if (object.amount === undefined) {
newObject = { ...newObject, amount: 0 }
}
return newObject
}
function join(a, b) {
const results = []
for (const aItem of a) {
const bItems = b.filter((item) => item.name === aItem.name)
let newObject
if (bItems.length) {
for (const bItem of bItems) {
newObject = { ...newObject, ...bItem }
}
newObject = fillMissingFields({ ...newObject, ...aItem })
} else {
newObject = fillMissingFields(aItem)
}
results.push(newObject)
}
return results
}
Besides the fact that it has a really bad time complexity O(n^2). It actually has a bug where if an object only appears in b array, that object will be omitted entirely from the new array.
Can anyone try to help me come up with a more robust and efficient algorithm to tackle this problem?
Make a collection whose keys are the names, whose values are the combined objects, which starts out with an undefined type and an amount of 0. Iterate through both arrays, assigning the property values as needed, then at the end, take the collection's values:
const a = [
{ name: 'apple', type: 'fruit' },
{ name: 'berry', type: 'fruit' },
{ name: 'grape', type: 'fruit' },
{ name: 'broccoli', type: 'vegetable' },
{ name: 'cabbage', type: 'vegetable' },
];
const b = [
{ name: 'apple', amount: 4 },
{ name: 'berry', amount: 5 },
{ name: 'grape', amount: 3 },
{ name: 'broccoli', amount: 7 },
{ name: 'avocado', amount: 8 },
];
const objsByName = new Map();
const getObj = (name) => {
if (!objsByName.has(name)) {
objsByName.set(name, { name, type: undefined, amount: 0 });
}
return objsByName.get(name);
};
for (const { name, type } of a) {
getObj(name).type = type;
}
for (const { name, amount } of b) {
getObj(name).amount = amount;
}
console.log([...objsByName.values()]);
This following approach will work for dynamic objects which have different keys other than name, type or amount. Although there is one problem with that approach we can not define default values for each variable(like for amount default will be 0 or for other key default will be undefined). In my approach if any key is missing in any of the object the default value will be undefined.
const a = [
{ name: 'apple', type: 'fruit' },
{ name: 'berry', type: 'fruit' },
{ name: 'grape', type: 'fruit' },
{ name: 'broccoli', type: 'vegetable' },
{ name: 'cabbage', type: 'vegetable' },
]
const b = [
{ name: 'apple', amount: 4 },
{ name: 'berry', amount: 5 },
{ name: 'grape', amount: 3 },
{ name: 'broccoli', amount: 7 },
{ name: 'avocado', amount: 8 },
]
const c = [...a, ...b];
const s = new Set();
let d = c.reduce((acc, curr) => {
const index = acc.findIndex(item => item.name === curr.name);
if(index > -1) {
acc[index] = {...acc[index], ...curr};
} else {
acc.push(curr);
}
Object.keys(curr).forEach(key => s.add(key));
return acc;
}, []);
let res = d.map(item => {
let keyInObj = Object.keys(item);
Array.from(s).forEach(actualKey => {
if(!keyInObj.includes(actualKey)) {
item[actualKey] = undefined;
}
});
return item;
})
console.log(res);
Please find below code snippet creating a unique array of objects out of two arrays. If value is not present in amount or type, we are writing 0 or undefined respectively.
const a = [
{ name: "apple", type: "fruit" },
{ name: "berry", type: "fruit" },
{ name: "grape", type: "fruit" },
{ name: "broccoli", type: "vegetable" },
{ name: "cabbage", type: "vegetable" },
];
const b = [
{ name: "apple", amount: 4 },
{ name: "berry", amount: 5 },
{ name: "grape", amount: 3 },
{ name: "broccoli", amount: 7 },
{ name: "avocado", amount: 8 },
];
let d = [...a, ...b];
const c = [];
d.map((o) => {
const uniqIndex = c.findIndex((item) => item.name === o.name);
uniqIndex === -1
? c.push({
amount: 0,
type: undefined,
...o,
})
: (c[uniqIndex] = {
...c[uniqIndex],
...o,
});
});
console.log(c);
I have an array of data which is a string of folders:
var data = [{ name: "/X" }, { name: "/X/Y" }, { name: "/X2" }, { name: "/X2/Z" }, { name: "/X/k" }]
For a component to display this items I need them sorted nested like these:
var data = [{ name: "/X", sub: [{ name: "/Y" }, { name: "/k" }]}, { name: "/X2" }, sub: [{ name: "/Z" }] }]
These items are just examples, the item count is 1000+ and the nested items can be unlimited too.
Any ideas how to do that?
You could do this with forEach and reduce methods and use one object to keep track of level based on the current part of the name property value.
const data = [{ name: "/X" }, { name: "/X/Y" }, { name: "/X2" }, { name: "/X2/Z" }, {name: '/X/K/1'}, {name: '/X/K/2'}]
const result = []
const level = {result}
data.forEach(({ name, ...rest }) => {
name.split('/').filter(Boolean).reduce((r, k) => {
if (!r[k]) {
r[k] = { result: [] }
r.result.push({
name: `/${k}`,
sub: r[k].result
})
}
return r[k]
}, level)
})
console.log(result)
Using reduce() and Map()
var data = [{ name: "/X" }, { name: "/X/Y" }, { name: "/X2" }, { name: "/X2/Z" }, { name: "/X/k" }]
var res = data.reduce((a, i) => {
let s = i.name.match(/\/\w+/g) || []
if (a.has(s[0])) {
let path = a.get(s[0])
i.name = s[1]
path.sub = path.sub || []
path.sub.push(i)
} else {
a.set(i.name, i)
}
return a
}, new Map())
console.log([...res.values()])
I have two arrays of objects and want to compare the name and value of them.
const array1 = [
{
name: 'John',
value: null
},
{
name: 'Peter',
value: null
}
]
const array2 = [
{
name: 'John',
value: '0'
}
]
If property name array2 exists on array1 then change the value of name with '0' else do nothing.
The result I expect is :
[
{
"name": "John",
"value": "0"
},
{
"name": "Peter",
"value": null
]
Can anyone show me how to do that?
You can use two forEach() loop for that:
const array1 = [
{
name: 'John',
value: null
},
{
name: 'Peter',
value: null
},
{
name: 'Mike',
value: null
}
]
const array2 = [
{
name: 'John',
value: '0'
},
{
name: 'Mike',
value: '0'
}
]
array2.forEach((item2) => {
array1.forEach((item1) => {
if(item1.name === item2.name){
item1.value = item2.value;
}
});
});
console.log(array1);
its simple :
array1.forEach(record1 => {
array2.forEach(record2 => {
if (record1.name === record2.name) {
record1.value = "0";
}
});
});
You can also map the first array and use find.
Please note this version of the code won't alter/mutate array1's content.
const array1 = [
{
name: 'John',
value: null
},
{
name: 'Peter',
value: null
}
];
const array2 = [
{
name: 'John',
value: '0'
}
];
const result = array1.map(item1 => {
const newItem = {...item1}
if(array2.find(item2 => item2.name === item1.name)) {
newItem.value = 0;
}
return newItem;
});
console.log(result);
its very simple:
you can user the below code :
array2.forEach(
function(parent){
array1.find(function(child)
{
if(child.name==parent.name){
child.value=0;
}
})
}
);
Try this:
const array1 = [
{
name: 'John',
value: null
},
{
name: 'Peter',
value: null
},
{
name: 'Mike',
value: null
}
]
const array2 = [
{
name: 'John',
value: '0'
},
{
name: 'Mike',
value: '0'
}
]
var array = array1.map(x=>{
if(array2.some(function (value) { return value.name === x.name })){
x.value = 0;
}
return x;
})