如何使用 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() 高阶函数将是实现此目的的最佳/现代/高效方法...如果是这样,怎么做?我有点陷入困境......我找到了关于这个主题的一些答案,但我无法使它们适应我的数组结构:-(

通过使用.reduce() and .find()组合:

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"
      }
    ]
  ]
]
   */