对象的嵌套reduce函数

3

我正在尝试缩小已经缩小的数组,并且在第二个reduce函数之后遇到了问题。在第二个函数运行之前,我的对象看起来是这样的:

const object = {
     groupA: [
       {name: "Adam", age: 25, Job: "Pharmacist", group: 'groupA'},
       {name: "Eric", age: 25, Job: "Vet", group: 'groupA'},
       {name: "Bob", age: 25, Job: "Pharmacist", group: 'groupA'},
       {name: "Peter", age: 25, Job: "Vet", group: 'groupA'},
     ],
    groupB: [
       {name: "Adam", age: 25, Job: "Pharmacist", group: 'groupB'},
       {name: "Eric", age: 25, Job: "Vet", group: 'groupB'},
       {name: "Bob", age: 25, Job: "Pharmacist", group: 'groupB'},
       {name: "Peter", age: 25, Job: "Vet", group: 'groupB'},
     ],    


 }


如果我想要获取类似于这样的结果,我应该使用哪个函数?

const object = {
     groupA: {
       pharmacist: [
         {name: "Adam", age: 25, Job: "Pharmacist", group: 'groupA'},
         {name: "Bob", age: 25, Job: "Pharmacist", group: 'groupA'},
      ],
      vet: [
       {name: "Eric", age: 25, Job: "Vet", group: 'groupA'},
       {name: "Peter", age: 25, Job: "Vet", group: 'groupA'},
      ]
     },
     groupB: {
       pharmacist: [
         {name: "Adam", age: 25, Job: "Pharmacist", group: 'groupB'},
         {name: "Bob", age: 25, Job: "Pharmacist", group: 'groupB'},
      ],
       vet: [
        {name: "Eric", age: 25, Job: "Vet", group: 'groupB'},
        {name: "Peter", age: 25, Job: "Vet", group: 'groupB'},
      ]
     }, 


 }


1
嘿@piotr.schaar。如果我假设你的初始数据结构是对象数组?(在被减少后,看起来像你在问题中提到的)。那么我实际上可以提供整个问题的解决方案,而不仅仅是第二部分。您可以调用groupBy(input,["group",“Job”]),它将返回所需的输出。您还可以像这样嵌套调用它,例如groupBy(input,["group",“Job”,“age”])-https://dev59.com/CLnoa4cB1Zd3GeqPYt3u#60741156 - Alex L
1
我之前在代码中有一个错误,这意味着它只能工作到2级深度分组,但现在它可以工作于N级深度分组 :) https://dev59.com/CLnoa4cB1Zd3GeqPYt3u#60741156 - Alex L
6个回答

3
你可以创建一个单独的函数来reduce()每个组,然后使用for..in将每个组未缩小的数组替换为缩小后的对象。

const object = {"groupA":[{"name":"Adam","age":25,"Job":"Pharmacist","group":"groupA"},{"name":"Eric","age":25,"Job":"Vet","group":"groupA"},{"name":"","age":25,"Job":"Pharmacist","group":"groupA"},{"name":"","age":25,"Job":"Vet","group":"groupA"}],"groupB":[{"name":"Adam","age":25,"Job":"Pharmacist","group":"groupB"},{"name":"Eric","age":25,"Job":"Vet","group":"groupB"},{"name":"","age":25,"Job":"Pharmacist","group":"groupB"},{"name":"","age":25,"Job":"Vet","group":"groupB"}]}

function groupByJob(arr){
  return arr.reduce((ac, a) => {
    if(!ac[a.Job]){
      ac[a.Job] = [];
    }
    ac[a.Job].push(a);
    return ac;
  }, {});
}

for(let k in object){
  object[k] = groupByJob(object[k]);
}
console.log(object)

如果您不想拆分,可以直接在object的条目上应用map(),然后直接在每个值上使用map()

const object = {"groupA":[{"name":"Adam","age":25,"Job":"Pharmacist","group":"groupA"},{"name":"Eric","age":25,"Job":"Vet","group":"groupA"},{"name":"","age":25,"Job":"Pharmacist","group":"groupA"},{"name":"","age":25,"Job":"Vet","group":"groupA"}],"groupB":[{"name":"Adam","age":25,"Job":"Pharmacist","group":"groupB"},{"name":"Eric","age":25,"Job":"Vet","group":"groupB"},{"name":"","age":25,"Job":"Pharmacist","group":"groupB"},{"name":"","age":25,"Job":"Vet","group":"groupB"}]}

const res = Object.fromEntries(
               Object.entries(object)
                 .map(([k, v]) => 
                    [  
                       k, 
                       v.reduce((ac, a) => 
                           (ac[a.Job] = (ac[a.Job] || []).concat(a), ac), 
                       {})
                    ]
                  )
                )

console.log(res)


2

您可以使用嵌套的reduce方法按工作分组创建新对象。

const object = {"groupA":[{"name":"Adam","age":25,"Job":"Pharmacist","group":"groupA"},{"name":"Eric","age":25,"Job":"Vet","group":"groupA"},{"name":"","age":25,"Job":"Pharmacist","group":"groupA"},{"name":"","age":25,"Job":"Vet","group":"groupA"}],"groupB":[{"name":"Adam","age":25,"Job":"Pharmacist","group":"groupB"},{"name":"Eric","age":25,"Job":"Vet","group":"groupB"},{"name":"","age":25,"Job":"Pharmacist","group":"groupB"},{"name":"","age":25,"Job":"Vet","group":"groupB"}]}

const result = Object.entries(object).reduce((r, [k, v]) => {
  r[k] = v.reduce((r, e) => {
    if (!r[e.Job]) r[e.Job] = [e]
    else r[e.Job].push(e)
    return r
  }, {})

  return r;
}, {})


console.log(result)


2

您可以使用Object.entries()获取您的object条目,然后使用.map()将每个值数组映射到基于键Job的分组对象。要对数组值进行分组,可以使用.reduce()通过累积包含每个关联Job的对象的数组值的对象来实现。然后,您可以使用Object.fromEntries()从映射的条目构建您的结果对象:

const object = { groupA: [ {name: "Adam", age: 25, Job: "Pharmacist", group: 'groupA'}, {name: "Eric", age: 25, Job: "Vet", group: 'groupA'}, {name: "Bob", age: 25, Job: "Pharmacist", group: 'groupA'}, {name: "Peter", age: 25, Job: "Vet", group: 'groupA'}, ], groupB: [ {name: "Adam", age: 25, Job: "Pharmacist", group: 'groupB'}, {name: "Eric", age: 25, Job: "Vet", group: 'groupB'}, {name: "Bob", age: 25, Job: "Pharmacist", group: 'groupB'}, {name: "Peter", age: 25, Job: "Vet", group: 'groupB'}, ], }
 
const res = Object.fromEntries(Object.entries(object).map(
  ([key, arr]) => [key, arr.reduce((acc, obj) => {
    acc[obj.Job] = [...(acc[obj.Job] || []), obj];
    return acc;
  }, {})]
));

console.log(res);

如果您无法支持Object.fromEntries(),则可以使用.map()将对象映射到[key,value]对数组中,然后将结果展开到Object.assign()中,如下所示:

const object = { groupA: [ {name: "Adam", age: 25, Job: "Pharmacist", group: 'groupA'}, {name: "Eric", age: 25, Job: "Vet", group: 'groupA'}, {name: "Bob", age: 25, Job: "Pharmacist", group: 'groupA'}, {name: "Peter", age: 25, Job: "Vet", group: 'groupA'}, ], groupB: [ {name: "Adam", age: 25, Job: "Pharmacist", group: 'groupB'}, {name: "Eric", age: 25, Job: "Vet", group: 'groupB'}, {name: "Bob", age: 25, Job: "Pharmacist", group: 'groupB'}, {name: "Peter", age: 25, Job: "Vet", group: 'groupB'}, ], }
 
const res = Object.assign({}, ...Object.entries(object).map(
  ([key, arr]) => ({[key]: arr.reduce((acc, obj) => {
    acc[obj.Job] = [...(acc[obj.Job] || []), obj];
    return acc;
  }, {})})
));

console.log(res);


1
我们可以这样做(嵌套reduce):

const input = {
     groupA: [
       {name: "Adam", age: 25, Job: "Pharmacist", group: 'groupA'},
       {name: "Eric", age: 25, Job: "Vet", group: 'groupA'},
       {name: "Bob", age: 26, Job: "Pharmacist", group: 'groupA'},
       {name: "Peter", age: 26, Job: "Vet", group: 'groupA'},
     ],
    groupB: [
       {name: "Adam", age: 25, Job: "Pharmacist", group: 'groupB'},
       {name: "Eric", age: 25, Job: "Vet", group: 'groupB'},
       {name: "Bob", age: 26, Job: "Pharmacist", group: 'groupB'},
       {name: "Peter", age: 26, Job: "Vet", group: 'groupB'},
     ]
 }
 
 const output = (property) => {
  return Object.entries(input).reduce((aggObj, [key,val]) => {
    const grouped = val.reduce((groupedObj, item) => {
      if (groupedObj.hasOwnProperty(item[property])){
        groupedObj[item[property]].push(item);
      } else{
        groupedObj[item[property]] = [item];
      }          
      return groupedObj;
    }, {});        
    aggObj[key] = grouped;        
    return aggObj;
  }, {})
 }
 console.log(output('Job'));
 //we could also do the same for age:
 //console.log(output('age'));

/* Desired output: */
/*
const output = {
     groupA: {
       pharmacist: [
         {name: "Adam", age: 25, Job: "Pharmacist", group: 'groupA'},
         {name: "Bob", age: 25, Job: "Pharmacist", group: 'groupA'},
      ],
      vet: [
       {name: "Eric", age: 25, Job: "Vet", group: 'groupA'},
       {name: "Peter", age: 25, Job: "Vet", group: 'groupA'},
      ]
     },
     groupB: {
       pharmacist: [
         {name: "Adam", age: 25, Job: "Pharmacist", group: 'groupB'},
         {name: "Bob", age: 25, Job: "Pharmacist", group: 'groupB'},
      ],
       vet: [
        {name: "Eric", age: 25, Job: "Vet", group: 'groupB'},
        {name: "Peter", age: 25, Job: "Vet", group: 'groupB'},
      ]
     }, 


 }
 */

本质上,使用 Object.entries(input) 从对象中创建一个可迭代对象

然后遍历这些 ([key, val]) 条目并提取键(即先是 "GroupA" 再是 "GroupB")

这些值(val)中的每一个都是一个数组,因此我们可以对其进行归约(即 val.reduce()

然后将与 item.Job 匹配的每个数组推送到分组对象中。

然后将其分配给最终返回的聚合对象并结束。

更新-递归解决方案,嵌套 N 层深

我想使它真正通用,并对初始数据的外观做出假设,并允许您在其他属性上执行此类嵌套分组(尽可能嵌套)。该功能在答案的下面显示(即三级深度分组),但现在,这是您的特定示例:

您可以像这样简单地调用它 groupBy(input, ["group", "Job"])

结果按组分组,然后按工作分组(嵌套)。

针对您的具体示例:

//assumed initial input, array of objects:
const input = [
  { name: "Adam", age: 25, Job: "Pharmacist", group: "groupA" },
  { name: "Eric", age: 25, Job: "Vet", group: "groupA" },
  { name: "Bob", age: 26, Job: "Pharmacist", group: "groupA" },
  { name: "Peter", age: 26, Job: "Vet", group: "groupA" },
  { name: "Adam", age: 25, Job: "Pharmacist", group: "groupB"},
  { name: "Eric", age: 25, Job: "Vet", group: "groupB" },
  { name: "Bob", age: 26, Job: "Pharmacist", group: "groupB" },
  { name: "Peter", age: 26, Job: "Vet", group: "groupB" }
];

const groupBy = (input, propertyArr) => {
  //console.log(propertyArr);
  const property = propertyArr[0];
  const grouped = input.reduce((groupedObj, item) => {
    groupedObj[item[property]] = [...(groupedObj[item[property]] || []), item];
    return groupedObj;
  }, {});
  if (propertyArr.length > 1) {
    //console.log(grouped);    
    return Object.keys(grouped).reduce((AggObj, key, index) => {
      const propertyArrCopy = [...propertyArr];
      propertyArrCopy.shift();
      AggObj[key] = groupBy(grouped[key], propertyArrCopy);
      return AggObj;
    }, {});
  } else {
    return grouped;
  }
};
console.log(groupBy(input, ["group", "Job"]));
.as-console-wrapper { max-height: 100% !important; top: 0; }

通过groupBy(input, ["group", "Job"]),我们可以得到您期望的输出结果:
{
  "groupA": {
    "Pharmacist": [
      {"name": "Adam", "age": 25, "Job": "Pharmacist", "group": "groupA"},
      {"name": "Bob", "age": 26, "Job": "Pharmacist", "group": "groupA"}
    ],
    "Vet": [
      {"name": "Eric", "age": 25, "Job": "Vet", "group": "groupA"},
      {"name": "Peter", "age": 26, "Job": "Vet", "group": "groupA"}
    ]
  },
  "groupB": {
    "Pharmacist": [
      {"name": "Adam", "age": 25, "Job": "Pharmacist", "group": "groupB"},
      {"name": "Bob", "age": 26, "Job": "Pharmacist", "group": "groupB"}
    ],
    "Vet": [
      {"name": "Eric", "age": 25, "Job": "Vet", "group": "groupB"},
      {"name": "Peter", "age": 26, "Job": "Vet", "group": "groupB"}
    ]
  }
}

更通用的解决方案在三级分组时的能力示例:

即调用groupBy(input, ["group", "Job", "age"])

结果按组、职业和年龄(嵌套)进行分组。

//assumed initial input, array of objects:
const input = [
  { name: "Adam", age: 25, Job: "Pharmacist", group: "groupA" },
  { name: "Lauren", age: 25, Job: "Pharmacist", group: "groupA" },
  { name: "Eric", age: 25, Job: "Vet", group: "groupA" },
  { name: "Theresa", age: 25, Job: "Vet", group: "groupA" },
  { name: "Bob", age: 26, Job: "Pharmacist", group: "groupA" },
  { name: "Brandy", age: 26, Job: "Pharmacist", group: "groupA" },
  { name: "Alex", age: 26, Job: "Scientist", group: "groupA" },
  { name: "Tom", age: 26, Job: "Scientist", group: "groupA" },
  { name: "Peter", age: 26, Job: "Vet", group: "groupA" },
  { name: "Kate", age: 26, Job: "Vet", group: "groupA" },
  { name: "Adam", age: 25, Job: "Pharmacist", group: "groupB" },
  { name: "Sarah", age: 25, Job: "Pharmacist", group: "groupB" },
  { name: "Eric", age: 25, Job: "Vet", group: "groupB" },
  { name: "Sophie", age: 25, Job: "Vet", group: "groupB" },
  { name: "Bob", age: 26, Job: "Pharmacist", group: "groupB" },
  { name: "Anne", age: 26, Job: "Pharmacist", group: "groupB" },
  { name: "Peter", age: 26, Job: "Vet", group: "groupB" },
  { name: "Mary", age: 26, Job: "Vet", group: "groupB" },
  { name: "Alex", age: 26, Job: "Scientist", group: "groupB" },
  { name: "Sarah", age: 26, Job: "Scientist", group: "groupB" }
];

const groupBy = (input, propertyArr) => {
  //console.log(propertyArr);
  const property = propertyArr[0];
  const grouped = input.reduce((groupedObj, item) => {
    groupedObj[item[property]] = [...(groupedObj[item[property]] || []), item];
    return groupedObj;
  }, {});
  if (propertyArr.length > 1) {
    //console.log(grouped);    
    return Object.keys(grouped).reduce((AggObj, key, index) => {
      const propertyArrCopy = [...propertyArr];
      propertyArrCopy.shift();
      AggObj[key] = groupBy(grouped[key], propertyArrCopy);
      return AggObj;
    }, {});
  } else {
    return grouped;
  }
};
console.log(groupBy(input, ["group", "Job", "age"]));
.as-console-wrapper { max-height: 100% !important; top: 0; }

我在初始数组中添加了更多的对象,使其更有趣。这也可以扩展到更大的数据集和更多层次的嵌套,并且应该能够正常工作。

0

你可以使用过滤器和归约函数

const object = {
     groupA: [
       {name: "Adam", age: 25, Job: "Pharmacist", group: 'groupA'},
       {name: "Eric", age: 25, Job: "Vet", group: 'groupA'},
       {name: "Name", age: 25, Job: "Pharmacist", group: 'groupA'},
       {name: "Name", age: 25, Job: "Vet", group: 'groupA'},
     ],
    groupB: [
       {name: "Adam", age: 25, Job: "Pharmacist", group: 'groupB'},
       {name: "Eric", age: 25, Job: "Vet", group: 'groupB'},
       {name: "Name", age: 25, Job: "Pharmacist", group: 'groupB'},
       {name: "Name", age: 25, Job: "Vet", group: 'groupB'},
     ],    
 }
 
 for(const key in object){
   object[key] = object[key]
   .map(a => a.Job)
   .filter((v,i,c)=> c.indexOf(v) === i)
   .reduce((acc, i) => ({...acc, [i]: object[key].filter(p => p.Job === i)}), {})
 }
 
 console.log(object)


0
编写函数arrToObj,将数组转换为具有分组键的对象。
将上述方法应用于对象中的所有条目,并构建一个新对象。

const object = {
  groupA: [
    { name: "Adam", age: 25, Job: "Pharmacist", group: "groupA" },
    { name: "Eric", age: 25, Job: "Vet", group: "groupA" },
    { name: "Bob", age: 25, Job: "Pharmacist", group: "groupA" },
    { name: "Peter", age: 25, Job: "Vet", group: "groupA" }
  ],
  groupB: [
    { name: "Adam", age: 25, Job: "Pharmacist", group: "groupB" },
    { name: "Eric", age: 25, Job: "Vet", group: "groupB" },
    { name: "Bob", age: 25, Job: "Pharmacist", group: "groupB" },
    { name: "Peter", age: 25, Job: "Vet", group: "groupB" }
  ]
};

const arrToObj = arr => {
  const res = {};
  arr.forEach(item => {
    if (!res[item.Job]) {
      res[item.Job] = [];
    }
    res[item.Job].push(item);
  });
  return res;
};

const newObject = Object.fromEntries(
  Object.entries(object).map(([key, value]) => [key, arrToObj(value)])
);

console.log(newObject);


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接