This question already has answers here:
Simplest code for array intersection in javascript
(40 answers)
Closed 4 years ago.
Let's say we have:
var array1 = [{ id: 1 }, { id: 4}, { id: 3 }]
var array2 = [{ id: 1 }, { id: 2}]
I know you can concat the two arrays like this (without having duplicates):
Array.from(new Set(array1.concat(array2)))
Now, how to create a new array with only the objects that share the same values?
var array2 = [{ id: 1 }]
You can use .filter() and .some() to extract matching elements:
let array1 = [{ id: 1 }, { id: 4}, { id: 3 }]
let array2 = [{ id: 1 }, { id: 2}]
let result = array1.filter(({id}) => array2.some(o => o.id === id));
console.log(result);
Useful Resources:
Array.prototype.filter()
Array.prototype.some()
You could take a set with the id of the objects and filter array2
var array1 = [{ id: 1 }, { id: 4}, { id: 3 }] ,
array2 = [{ id: 1 }, { id: 2}],
s = new Set(array1.map(({ id }) => id)),
common = array2.filter(({ id }) => s.has(id));
console.log(common);
The requested sameness with identical objects.
var array1 = [{ id: 1 }, { id: 4}, { id: 3 }] ,
array2 = [array1[0], { id: 2}],
s = new Set(array1),
common = array2.filter(o => s.has(o));
console.log(common);
Assuming, by your definition, that the objects, even if they have the same structure, are not really the same object, I define an 'equality function', and then, with filter and some:
var array1 = [{ id: 1 }, { id: 4}, { id: 3 }]
var array2 = [{ id: 1 }, { id: 2}];
var equal = function(o1, o2) { return o1.id === o2.id };
var result = array2.filter(function(item1) {
return array1.some(function(item2) { return equal(item1, item2) });
});
console.log(result);
I have an array with objects smth like this:
arr = [
{name: 'Igor', id: 1,....},
{name: 'Anton', id: 1,.... },
{name: 'Igor', id: 2,.... },
{name: 'Peter', id: 2,.... },
{name: 'Igor', id: 2,.... }
]
I need to get new array like:
arrId = [
{ id: 1, names: 'Igor, Anton' },
{ id: 2, names: 'Igor, Peter' }
]
can't think of good solution
In this example I use map and reduce.
function rearrange(arr) {
// use `reduce` to build an object using the ids as keys
// this allows us to place all the names with the same id together
// note we pass in an empty object to act as our initial p argument.
var out = arr.reduce(function (p, c) {
var key = c.id, name = c.name;
// if the key doesn't exist create it and set its value
// to an empty array
p[key] = p[key] || [];
// add the name to the array if it doesn't already exist
if (p[key].indexOf(name) === -1) p[key].push(name);
return p;
}, {});
// use `map` to return an array of objects
return Object.keys(out).map(function (el) {
// make sure we use an integer for the id, and
// join the array to get the appropriate output
return { id: +el, names: out[el].join(', ') };
});
}
rearrange(arr);
DEMO
OUTPUT
[
{
"id": 1,
"names": "Igor, Anton"
},
{
"id": 2,
"names": "Igor, Peter"
}
]
You can use reduce function
arr = [
{name: 'Igor', id: 1},
{name: 'Anton', id: 1 },
{name: 'Igor', id: 2 },
{name: 'Peter', id: 2 },
{name: 'Igor', id: 2 }
]
//first group needed fields from items by id
var result = arr.reduce(function(acc,cur){
if(!acc.map[cur.id]) {
acc.map[cur.id] = {id:cur.id, names:{}};
acc.result.push(acc.map[cur.id]);
}
acc.map[cur.id].names[cur.name]=true;
return acc;
},{map:{},result:[]})
//do addtional transfrom from map object with names, to string separated by comma
.result.map(function(el){
return {id:el.id, names: Object.keys(el.names).join(', ')};
});
console.log(result);
document.body.innerHTML = JSON.stringify(result,null, 2);
var arrId = [];
var arrKey = {};
for( var counter = 0; counter < arr.length; counter++)
{
var arrObj = arr[ counter ];
if ( !arrKey[ arrObj[ "id" ] ] )
{
arrKey[ arrObj[ "id" ] ] = [];
}
arrKey[ arrObj[ "id" ] ].push( arrObj[ "name" ] );
}
for ( var id in arrKey )
{
arrId.push( [ "id": id, names : arrKey[ id ].join( "," ) ] );
}
console.log(arrId );
What is the best way to merge array contents from JavaScript objects sharing a key in common?
How can array in the example below be reorganized into output? Here, all value keys (whether an array or not) are merged into all objects sharing the same name key.
var array = [
{
name: "foo1",
value: "val1"
}, {
name: "foo1",
value: [
"val2",
"val3"
]
}, {
name: "foo2",
value: "val4"
}
];
var output = [
{
name: "foo1",
value: [
"val1",
"val2",
"val3"
]
}, {
name: "foo2",
value: [
"val4"
]
}
];
Here is one option:-
var array = [{
name: "foo1",
value: "val1"
}, {
name: "foo1",
value: ["val2", "val3"]
}, {
name: "foo2",
value: "val4"
}];
var output = [];
array.forEach(function(item) {
var existing = output.filter(function(v, i) {
return v.name == item.name;
});
if (existing.length) {
var existingIndex = output.indexOf(existing[0]);
output[existingIndex].value = output[existingIndex].value.concat(item.value);
} else {
if (typeof item.value == 'string')
item.value = [item.value];
output.push(item);
}
});
console.dir(output);
Here is another way of achieving that goal:
var array = [{
name: "foo1",
value: "val1"
}, {
name: "foo1",
value: [
"val2",
"val3"
]
}, {
name: "foo2",
value: "val4"
}];
var output = array.reduce(function(o, cur) {
// Get the index of the key-value pair.
var occurs = o.reduce(function(n, item, i) {
return (item.name === cur.name) ? i : n;
}, -1);
// If the name is found,
if (occurs >= 0) {
// append the current value to its list of values.
o[occurs].value = o[occurs].value.concat(cur.value);
// Otherwise,
} else {
// add the current item to o (but make sure the value is an array).
var obj = {
name: cur.name,
value: [cur.value]
};
o = o.concat([obj]);
}
return o;
}, []);
console.log(output);
2021 version
Using reduce to aggregate data.
Using logical nullish assignment only assigns if acc[name] is nullish (null or undefined).
Using Array.isArray to determines whether the passed value is an Array.
var arrays = [{ name: "foo1",value: "val1" }, {name: "foo1", value: ["val2", "val3"] }, {name: "foo2",value: "val4"}];
const result = arrays.reduce((acc, {name, value}) => {
acc[name] ??= {name: name, value: []};
if(Array.isArray(value)) // if it's array type then concat
acc[name].value = acc[name].value.concat(value);
else
acc[name].value.push(value);
return acc;
}, {});
console.log(Object.values(result));
Using lodash
var array = [{name:"foo1",value:"val1"},{name:"foo1",value:["val2","val3"]},{name:"foo2",value:"val4"}];
function mergeNames (arr) {
return _.chain(arr).groupBy('name').mapValues(function (v) {
return _.chain(v).pluck('value').flattenDeep();
}).value();
}
console.log(mergeNames(array));
Here is a version using an ES6 Map:
const arrays = [{ name: "foo1",value: "val1" }, {name: "foo1", value: ["val2", "val3"] }, {name: "foo2",value: "val4"}];
const map = new Map(arrays.map(({name, value}) => [name, { name, value: [] }]));
for (let {name, value} of arrays) map.get(name).value.push(...[value].flat());
console.log([...map.values()]);
Use lodash "uniqWith". As shown below
let _ = require("lodash");
var array = [
{ name: "foo1", value: "1" },
{ name: "foo1", value: "2" },
{ name: "foo2", value: "3" },
{ name: "foo1", value: "4" }
];
let merged = _.uniqWith(array, (pre, cur) => {
if (pre.name == cur.name) {
cur.value = cur.value + "," + pre.value;
return true;
}
return false;
});
console.log(merged);
// output: [{ name: "foo1", value: "1,2,4" }, { name: "foo2", value: "3" }];
Using reduce:
var mergedObj = array.reduce((acc, obj) => {
if (acc[obj.name]) {
acc[obj.name].value = acc[obj.name].value.isArray ?
acc[obj.name].value.concat(obj.value) :
[acc[obj.name].value].concat(obj.value);
} else {
acc[obj.name] = obj;
}
return acc;
}, {});
let output = [];
for (let prop in mergedObj) {
output.push(mergedObj[prop])
}
It's been a while since this question was asked, but I thought I'd chime in as well. For functions like this that execute a basic function you'll want to use over and over, I prefer to avoid longer-written functions and loops if I can help it and develop the function as a one-liner using shallow Array.prototype functions like .map() and some other ES6+ goodies like Object.entries() and Object.fromEntries(). Combining all these, we can execute a function like this relatively easily.
First, I take in however many objects you pass to the function as a rest parameter and prepend that with an empty object we'll use to collect all the keys and values.
[{}, ...objs]
Next, I use the .map() Array prototype function paired with Object.entries() to loop through all the entries of each object, and any sub-array elements each contains and then either set the empty object's key to that value if it has not yet been declared, or I push the new values to the object key if it has been declared.
[{},...objs].map((e,i,a) => i ? Object.entries(e).map(f => (a[0][f[0]] ? a[0][f[0]].push(...([f[1]].flat())) : (a[0][f[0]] = [f[1]].flat()))) : e)[0]
Finally, to replace any single-element-arrays with their contained value, I run another .map() function on the result array using both Object.entries() and Object.fromEntries(), similar to how we did before.
let getMergedObjs = (...objs) => Object.fromEntries(Object.entries([{},...objs].map((e,i,a) => i ? Object.entries(e).map(f => (a[0][f[0]] ? a[0][f[0]].push(...([f[1]].flat())) : (a[0][f[0]] = [f[1]].flat()))) : e)[0]).map(e => e.map((f,i) => i ? (f.length > 1 ? f : f[0]) : f)));
This will leave you with the final merged object, exactly as you prescribed it.
let a = {
a: [1,9],
b: 1,
c: 1
}
let b = {
a: 2,
b: 2
}
let c = {
b: 3,
c: 3,
d: 5
}
let getMergedObjs = (...objs) => Object.fromEntries(Object.entries([{},...objs].map((e,i,a) => i ? Object.entries(e).map(f => (a[0][f[0]] ? a[0][f[0]].push(...([f[1]].flat())) : (a[0][f[0]] = [f[1]].flat()))) : e)[0]).map(e => e.map((f,i) => i ? (f.length > 1 ? f : f[0]) : f)));
getMergedObjs(a,b,c); // { a: [ 1, 9, 2 ], b: [ 1, 2, 3 ], c: [ 1, 3 ], d: 5 }
Try this:
var array = [{name:"foo1",value:"val1"},{name:"foo1",value:["val2","val3"]},{name:"foo2",value:"val4"},{name:"foo2",value:"val5"}];
for(var j=0;j<array.length;j++){
var current = array[j];
for(var i=j+1;i<array.length;i++){
if(current.name = array[i].name){
if(!isArray(current.value))
current.value = [ current.value ];
if(isArray(array[i].value))
for(var v=0;v<array[i].value.length;v++)
current.value.push(array[i].value[v]);
else
current.value.push(array[i].value);
array.splice(i,1);
i++;
}
}
}
function isArray(myArray) {
return myArray.constructor.toString().indexOf("Array") > -1;
}
document.write(JSON.stringify(array));
This work too !
var array = [
{
name: "foo1",
value: "val1",
},
{
name: "foo1",
value: ["val2", "val3"],
},
{
name: "foo2",
value: "val4",
},
];
let arr2 = [];
array.forEach((element) => { // remove duplicate name
let match = arr2.find((r) => r.name == element.name);
if (match) {
} else {
arr2.push({ name: element.name, value: [] });
}
});
arr2.map((item) => {
array.map((e) => {
if (e.name == item.name) {
if (typeof e.value == "object") { //lets map if value is an object
e.value.map((z) => {
item.value.push(z);
});
} else {
item.value.push(e.value);
}
}
});
});
console.log(arr2);
const exampleObj = [{
year: 2016,
abd: 123
}, {
year: 2016,
abdc: 123
}, {
year: 2017,
abdcxc: 123
}, {
year: 2017,
abdcxcx: 123
}];
const listOfYears = [];
const finalObj = [];
exampleObj.map(sample => {
listOfYears.push(sample.year);
});
const uniqueList = [...new Set(listOfYears)];
uniqueList.map(list => {
finalObj.push({
year: list
});
});
exampleObj.map(sample => {
const sampleYear = sample.year;
finalObj.map((obj, index) => {
if (obj.year === sampleYear) {
finalObj[index] = Object.assign(sample, obj);
}
});
});
The final object be [{"year":2016,"abdc":123,"abd":123},{"year":2017,"abdcxcx":123,"abdcxc":123}]
const array = [{ name: "foo1", value: "val1" }, {name: "foo1", value: ["val2", "val3"] }, {name: "foo2", value: "val4"}];
const start = array.reduce((object, {name}) => ({...object, [name]: []}), {});
const result = array.reduce((object, {name, value}) => ({...object, [name]: [object[name], [value]].flat(2)}), start);
const output = Object.entries(result).map(([name, value]) => ({name: name, value: value}));
console.log(output);
try this :
var array = [
{
name: "foo1",
value: "val1"
}, {
name: "foo1",
value: [
"val2",
"val3"
]
}, {
name: "foo2",
value: "val4"
}
];
var output = [
{
name: "foo1",
value: [
"val1",
"val2",
"val3"
]
}, {
name: "foo2",
value: [
"val4"
]
}
];
bb = Object.assign( {}, array, output );
console.log(bb) ;
A much more easier approach is this 2022:
var array = [
{
name: "foo1",
value: "val1"
}, {
name: "foo1",
value: [
"val2",
"val3"
]
}, {
name: "foo2",
value: "val4"
}
];
var output = [
{
name: "foo1",
value: [
"val1",
"val2",
"val3"
]
},
{
name: "foo2",
value: [
"val4"
]
}
];
function mergeBasedOnKey(list){
let c = Object.values(list.reduce((a, b) => {
a[b.name] = a[b.name] || {name: b.name, value: []}
if(typeof(b['value']) == "string"){
a[b.name].value.push(b['value'])
}
else{
a[b.name].value = [...a[b.name].value, ...b.value]
}
return a
}, {}))
return c
}
let ans = mergeBasedOnKey(array)
console.log(ans)
I was looking for a quick, almost "one-liner" answer in this thread, provided that this is a trivial but common exercise.
I couldn't find any for my like. The other answers are fine but I am not much into boilerplate.
So, let me add one, then:
o = array.reduce((m,{name:n,value:v})=>({...m,[n]:[...m[n]||[],v].flat(1)}),{})
output = Object.entries(o).map(([n,v])=>({name:n,value:v}))
var array = [
{ name: "foo1", value: "val1"},
{ name: "foo1", value: ["val2","val3"] },
{ name: "foo2", value: "val4" }
]
o=array.reduce((m,{name:n,value:v})=>({...m,[n]:[...m[n]||[],v].flat(1)}),{})
output=Object.entries(o).map(([n,v])=>({name:n,value:v}))
console.log(output)