如何使用 reduce() 按对象 属性 对数组进行分组
How to group array by an object property with reduce()
基于一个数组,我想创建一个新数组,该数组由包含的对象的 属性 'desc'
分组。像这样:
const sourceArray = [
{ id: 'id1', sourceDesc: 'foo', prop1: 'ignoreme', prop2: 'ignoreme' }
{ id: 'id2', sourceDesc: 'foo', prop1: 'ignoreme', prop2: 'ignoreme' }
{ id: 'id3', sourceDesc: 'bar', prop1: 'ignoreme', prop2: 'ignoreme' }
{ id: 'id4', sourceDesc: 'baz', prop1: 'ignoreme', prop2: 'ignoreme' }
];
const targetArray = [
{ desc: 'foo', ids: [
{ id: 'id1', prop1: 'ignoreme', prop2: 'ignoreme' },
{ id: 'id2', prop1: 'ignoreme', prop2: 'ignoreme' }
]},
{ desc: 'bar', ids: [
{ id: 'id3', prop1: 'ignoreme', prop2: 'ignoreme' }
]},
{ desc: 'baz', ids: [
{ id: 'id4', prop1: 'ignoreme', prop2: 'ignoreme' }
]}
];
我想 reduce()
高阶函数将是实现此目的的最佳/现代/高效方法...如果是这样,怎么做?我有点陷入困境......我找到了关于这个主题的一些答案,但我无法使它们适应我的数组结构:-(
const sourceArray = [
{ id: 'id1', sourceDesc: 'foo', prop1: 'ignoreme', prop2: 'ignoreme' },
{ id: 'id2', sourceDesc: 'foo', prop1: 'ignoreme', prop2: 'ignoreme' },
{ id: 'id3', sourceDesc: 'bar', prop1: 'ignoreme', prop2: 'ignoreme' },
{ id: 'id4', sourceDesc: 'baz', prop1: 'ignoreme', prop2: 'ignoreme' }
];
const result = sourceArray.reduce((a, c) => {
const found = a.find(e => e.desc === c.sourceDesc);
if (found) found.ids.push({
id: c.id,
prop1: c.prop1,
prop2: c.prop2
});
else a.push({
desc: c.sourceDesc,
ids: [{
id: c.id,
prop1: c.prop1,
prop2: c.prop2
}]
});
return a;
}, []);
console.log(result);
您可以使用 .reduce()
along-with Object.entries()
and .map()
方法获得所需的输出:
const data = [
{ id: 'id1', sourceDesc: 'foo', prop1: 'ignoreme', prop2: 'ignoreme' },
{ id: 'id2', sourceDesc: 'foo', prop1: 'ignoreme', prop2: 'ignoreme' },
{ id: 'id3', sourceDesc: 'bar', prop1: 'ignoreme', prop2: 'ignoreme' },
{ id: 'id4', sourceDesc: 'baz', prop1: 'ignoreme', prop2: 'ignoreme' }
];
const reducer = (arr) => Object.entries(
arr.reduce((r, { sourceDesc:desc, ...rest }) => {
r[desc] = r[desc] || [];
r[desc].push(rest);
return r;
}, {})
).map(([k, v]) => ({desc: k, ids: v}));
console.log(reducer(data));
.as-console-wrapper { max-height: 100% !important; top: 0; }
我们可以使用 forEach
并使用 sourceDesc
键构建对象
const sourceArray = [
{ id: "id1", sourceDesc: "foo", prop1: "ignoreme", prop2: "ignoreme" },
{ id: "id2", sourceDesc: "foo", prop1: "ignoreme", prop2: "ignoreme" },
{ id: "id3", sourceDesc: "bar", prop1: "ignoreme", prop2: "ignoreme" },
{ id: "id4", sourceDesc: "baz", prop1: "ignoreme", prop2: "ignoreme" }
];
const update = data => {
const res = {};
data.forEach(({ sourceDesc, ...item }) => {
if (!res[sourceDesc]) {
res[sourceDesc] = { desc: sourceDesc, ids: [] };
}
res[sourceDesc].ids.push(item);
});
return Object.values(res);
};
console.log(update(sourceArray));
你可以像这样使用 reduce
const sourceArray = [
{ id: 'id1', 'sourceDesc': 'foo', 'prop1': 'ignoreme', 'prop2': 'ignoreme' },
{ id: 'id2', 'sourceDesc': 'foo', 'prop1': 'ignoreme', 'prop2': 'ignoreme' },
{ id: 'id3', 'sourceDesc': 'bar', 'prop1': 'ignoreme', 'prop2': 'ignoreme' },
{ 'id': 'id4', 'sourceDesc': 'baz', 'prop1': 'ignoreme', 'prop2': 'ignoreme' }
];
const final = sourceArray.reduce((op,{id,sourceDesc,prop1,prop2})=>{
let key= sourceDesc
op[key] = op[key] || {des:sourceDesc, ids:[]}
op[key].ids.push({id,prop1,prop2})
return op
},{})
console.log(Object.values(final))
您可以将数组缩减为 Map,使用 sourceDesc
作为键,然后将 Map.values()
迭代器扩展回数组:
const sourceArray = [
{ id: 'id1', sourceDesc: 'foo', prop1: 'ignoreme', prop2: 'ignoreme' },
{ id: 'id2', sourceDesc: 'foo', prop1: 'ignoreme', prop2: 'ignoreme' },
{ id: 'id3', sourceDesc: 'bar', prop1: 'ignoreme', prop2: 'ignoreme' },
{ id: 'id4', sourceDesc: 'baz', prop1: 'ignoreme', prop2: 'ignoreme' }
];
const result = [...
sourceArray.reduce((r, { sourceDesc: desc, ...o }) => {
if(!r.has(desc)) r.set(desc, { desc, ids: [] }); // add the group if doesn't exist
r.get(desc).ids.push(o); // add the object to the group
return r;
}, new Map)
.values()]; // spread the Map's values to get an array
console.log(result);
这是另一种使用映射的方法,JSON array to Group by key:
const sourceArray = [{"id":"id1","sourceDesc":"foo","prop1":"ignoreme","prop2":"ignoreme"},{"id":"id2","sourceDesc":"foo","prop1":"ignoreme","prop2":"ignoreme"},{"id":"id3","sourceDesc":"bar","prop1":"ignoreme","prop2":"ignoreme"},{"id":"id4","sourceDesc":"baz","prop1":"ignoreme","prop2":"ignoreme"}];
const key = 'sourceDesc';
const arrayUniqueByKey1 = [...new Map(sourceArray.map(item =>
[item[key], sourceArray.filter(x=>x[key] == item[key])]))
/*remove following comment to get flat array*/ //.values()
];
console.log(arrayUniqueByKey1);
/*OUTPUT Format
[
[
"foo",
[
{
"id": "id1",
"sourceDesc": "foo",
"prop1": "ignoreme",
"prop2": "ignoreme"
},
{
"id": "id2",
"sourceDesc": "foo",
"prop1": "ignoreme",
"prop2": "ignoreme"
}
]
]
]
*/
基于一个数组,我想创建一个新数组,该数组由包含的对象的 属性 'desc'
分组。像这样:
const sourceArray = [
{ id: 'id1', sourceDesc: 'foo', prop1: 'ignoreme', prop2: 'ignoreme' }
{ id: 'id2', sourceDesc: 'foo', prop1: 'ignoreme', prop2: 'ignoreme' }
{ id: 'id3', sourceDesc: 'bar', prop1: 'ignoreme', prop2: 'ignoreme' }
{ id: 'id4', sourceDesc: 'baz', prop1: 'ignoreme', prop2: 'ignoreme' }
];
const targetArray = [
{ desc: 'foo', ids: [
{ id: 'id1', prop1: 'ignoreme', prop2: 'ignoreme' },
{ id: 'id2', prop1: 'ignoreme', prop2: 'ignoreme' }
]},
{ desc: 'bar', ids: [
{ id: 'id3', prop1: 'ignoreme', prop2: 'ignoreme' }
]},
{ desc: 'baz', ids: [
{ id: 'id4', prop1: 'ignoreme', prop2: 'ignoreme' }
]}
];
我想 reduce()
高阶函数将是实现此目的的最佳/现代/高效方法...如果是这样,怎么做?我有点陷入困境......我找到了关于这个主题的一些答案,但我无法使它们适应我的数组结构:-(
const sourceArray = [
{ id: 'id1', sourceDesc: 'foo', prop1: 'ignoreme', prop2: 'ignoreme' },
{ id: 'id2', sourceDesc: 'foo', prop1: 'ignoreme', prop2: 'ignoreme' },
{ id: 'id3', sourceDesc: 'bar', prop1: 'ignoreme', prop2: 'ignoreme' },
{ id: 'id4', sourceDesc: 'baz', prop1: 'ignoreme', prop2: 'ignoreme' }
];
const result = sourceArray.reduce((a, c) => {
const found = a.find(e => e.desc === c.sourceDesc);
if (found) found.ids.push({
id: c.id,
prop1: c.prop1,
prop2: c.prop2
});
else a.push({
desc: c.sourceDesc,
ids: [{
id: c.id,
prop1: c.prop1,
prop2: c.prop2
}]
});
return a;
}, []);
console.log(result);
您可以使用 .reduce()
along-with Object.entries()
and .map()
方法获得所需的输出:
const data = [
{ id: 'id1', sourceDesc: 'foo', prop1: 'ignoreme', prop2: 'ignoreme' },
{ id: 'id2', sourceDesc: 'foo', prop1: 'ignoreme', prop2: 'ignoreme' },
{ id: 'id3', sourceDesc: 'bar', prop1: 'ignoreme', prop2: 'ignoreme' },
{ id: 'id4', sourceDesc: 'baz', prop1: 'ignoreme', prop2: 'ignoreme' }
];
const reducer = (arr) => Object.entries(
arr.reduce((r, { sourceDesc:desc, ...rest }) => {
r[desc] = r[desc] || [];
r[desc].push(rest);
return r;
}, {})
).map(([k, v]) => ({desc: k, ids: v}));
console.log(reducer(data));
.as-console-wrapper { max-height: 100% !important; top: 0; }
我们可以使用 forEach
并使用 sourceDesc
const sourceArray = [
{ id: "id1", sourceDesc: "foo", prop1: "ignoreme", prop2: "ignoreme" },
{ id: "id2", sourceDesc: "foo", prop1: "ignoreme", prop2: "ignoreme" },
{ id: "id3", sourceDesc: "bar", prop1: "ignoreme", prop2: "ignoreme" },
{ id: "id4", sourceDesc: "baz", prop1: "ignoreme", prop2: "ignoreme" }
];
const update = data => {
const res = {};
data.forEach(({ sourceDesc, ...item }) => {
if (!res[sourceDesc]) {
res[sourceDesc] = { desc: sourceDesc, ids: [] };
}
res[sourceDesc].ids.push(item);
});
return Object.values(res);
};
console.log(update(sourceArray));
你可以像这样使用 reduce
const sourceArray = [
{ id: 'id1', 'sourceDesc': 'foo', 'prop1': 'ignoreme', 'prop2': 'ignoreme' },
{ id: 'id2', 'sourceDesc': 'foo', 'prop1': 'ignoreme', 'prop2': 'ignoreme' },
{ id: 'id3', 'sourceDesc': 'bar', 'prop1': 'ignoreme', 'prop2': 'ignoreme' },
{ 'id': 'id4', 'sourceDesc': 'baz', 'prop1': 'ignoreme', 'prop2': 'ignoreme' }
];
const final = sourceArray.reduce((op,{id,sourceDesc,prop1,prop2})=>{
let key= sourceDesc
op[key] = op[key] || {des:sourceDesc, ids:[]}
op[key].ids.push({id,prop1,prop2})
return op
},{})
console.log(Object.values(final))
您可以将数组缩减为 Map,使用 sourceDesc
作为键,然后将 Map.values()
迭代器扩展回数组:
const sourceArray = [
{ id: 'id1', sourceDesc: 'foo', prop1: 'ignoreme', prop2: 'ignoreme' },
{ id: 'id2', sourceDesc: 'foo', prop1: 'ignoreme', prop2: 'ignoreme' },
{ id: 'id3', sourceDesc: 'bar', prop1: 'ignoreme', prop2: 'ignoreme' },
{ id: 'id4', sourceDesc: 'baz', prop1: 'ignoreme', prop2: 'ignoreme' }
];
const result = [...
sourceArray.reduce((r, { sourceDesc: desc, ...o }) => {
if(!r.has(desc)) r.set(desc, { desc, ids: [] }); // add the group if doesn't exist
r.get(desc).ids.push(o); // add the object to the group
return r;
}, new Map)
.values()]; // spread the Map's values to get an array
console.log(result);
这是另一种使用映射的方法,JSON array to Group by key:
const sourceArray = [{"id":"id1","sourceDesc":"foo","prop1":"ignoreme","prop2":"ignoreme"},{"id":"id2","sourceDesc":"foo","prop1":"ignoreme","prop2":"ignoreme"},{"id":"id3","sourceDesc":"bar","prop1":"ignoreme","prop2":"ignoreme"},{"id":"id4","sourceDesc":"baz","prop1":"ignoreme","prop2":"ignoreme"}];
const key = 'sourceDesc';
const arrayUniqueByKey1 = [...new Map(sourceArray.map(item =>
[item[key], sourceArray.filter(x=>x[key] == item[key])]))
/*remove following comment to get flat array*/ //.values()
];
console.log(arrayUniqueByKey1);
/*OUTPUT Format
[
[
"foo",
[
{
"id": "id1",
"sourceDesc": "foo",
"prop1": "ignoreme",
"prop2": "ignoreme"
},
{
"id": "id2",
"sourceDesc": "foo",
"prop1": "ignoreme",
"prop2": "ignoreme"
}
]
]
]
*/