[英]Merge JavaScript objects in array with same key
What is the best way to merge array contents from JavaScript objects sharing a key in common?从共享一个共同键的 JavaScript 对象中合并数组内容的最佳方法是什么?
How can array
in the example below be reorganized into output
?下面示例中的
array
如何重组为output
? Here, all value
keys ( whether an array or not ) are merged into all objects sharing the same name
key.在这里,所有
value
键(无论是否为数组)都被合并到共享相同name
键的所有对象中。
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);
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:这是一个使用 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()]);
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));
2021 version 2021版
reduce
to aggregate data.reduce
来聚合数据。logical nullish assignment
only assigns if acc[name]
is nullish ( null or undefined
).acc[name]
为空( null or undefined
)时才使用logical nullish assignment
。Array.isArray
to determines whether the passed value is an Array
.Array.isArray
判断传入的值是否为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 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])
}
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}]最终对象是 [{"year":2016,"abdc":123,"abd":123},{"year":2017,"abdcxcx":123,"abdcxc":123}]
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);
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) ;
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()
.对于像这样执行基本函数的函数,你会想要一遍又一遍地使用,如果我可以帮助它并使用浅层 Array.prototype 函数将函数开发为单行函数,我更愿意避免编写较长的函数和循环
.map()
和其他一些 ES6+ 好东西,比如Object.entries()
和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.首先,我接受你传递给函数的许多对象作为一个 rest 参数,并在它前面加上一个空对象,我们将用它来收集所有的键和值。
[{}, ...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.接下来,我使用与
Object.entries()
配对的.map()
数组原型函数来循环遍历每个对象的所有条目,以及每个包含的任何子数组元素,然后将空对象的键设置为该值,如果它尚未声明,或者我将新值推送到对象键(如果已声明)。
[{},...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.最后,为了用它们包含的值替换任何单元素数组,我使用
Object.entries()
和Object.fromEntries()
在结果数组上运行另一个.map()
函数,类似于我们之前所做的。
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 }
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" }];
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);
A much more easier approach is this 2022:更简单的方法是 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(2)}),{})
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" } ] obj= array.reduce((o,{name:n,value:v})=>({...o,[n]:[...(o[n]||[]),v].flat(2)}),{}) output= Object.entries(obj).map(([n,v])=>({name:n,value:v})) console.log(output)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.