基于嵌套数组重新组合对象数组

Posted

技术标签:

【中文标题】基于嵌套数组重新组合对象数组【英文标题】:Regroup array of objects based on nested array 【发布时间】:2020-03-12 08:18:13 【问题描述】:

我有一个对象数组。每个对象包含另一个内部数组。我想将每个内部数组作为外部对象,并将剩余的旧外部元素作为新创建的外部对象的子属性。

输入

data = [
    
      name: "Sam",
      ssn: 123,
      age: 25,
      hobbies: [ name: "cricket" ,  name: "football" ]
    ,
    
      name: "John",
      ssn: 234,
      age: 25,
      hobbies: [ name: "cricket" ,  name: "football" ]
    ,
    
      name: "Mathew",
      ssn: 345,
      age: 25,
      hobbies: [ name: "cricket" ,  name: "football" , name: "carroms"]
    
  ];

预期输出

[
      
        name: "cricket",
        person_details: [
           name: "Sam", ssn: 123, age: 25 ,
           name: "John", ssn: 234, age: 25 ,
           name: "Mathew", ssn: 345, age: 25 
        ]
      ,
      
        name: "football",
        person_details: [
           name: "Sam", ssn: 123, age: 25 ,
           name: "John", ssn: 234, age: 25 ,
           name: "Mathew", ssn: 345, age: 25 
        ]
      ,
      
        name: "carroms",
        person_details: [          
           name: "Mathew", ssn: 345, age: 25 
        ]
      
    ]

我使用 Reduce 的尝试如下

this.data = this.data.reduce(
  (a, x) => [...x.hobbies.map(h => ( ...x, hobbies: [h] ))],
  []
);

【问题讨论】:

为什么要在输出中输入hobbies:?你为什么不在循环中访问h.name 当我看到这样的代码时,我想知道你是不是在尝试,或者你只是随机地将一些东西放在一起,所以我们不会因为没有显示尝试而关闭问题。 嘿伙计。我尝试了一些东西,但我不清楚如何通过添加扩展、箭头、es6 功能来简单地实现这一点。这可以很容易地使用多个 for 循环来完成,但我的目的是尽量减少复杂性和代码。 使用 spread 和 reduce 来缩短代码并不总能最小化复杂性。写清楚。 【参考方案1】:

您可以减少数组并为结果集寻找相同名称的项目。

var data = [ name: "Sam", ssn: 123, age: 25, hobbies: [ name: "cricket" ,  name: "football" ] ,  name: "John", ssn: 234, age: 25, hobbies: [ name: "cricket" ,  name: "football" ] ,  name: "Mathew", ssn: 345, age: 25, hobbies: [ name: "cricket" ,  name: "football" ,  name: "carroms" ] ],
    result = data.reduce((r,  hobbies, ...o ) => 
        hobbies.forEach(( name ) => 
            var group = r.find(q => q.name === name);
            if (!group) r.push(group =  name, person_details: [] );
            group.person_details.push(o);
        )
        return r;
    , []);

console.log(result);
.as-console-wrapper  max-height: 100% !important; top: 0; 

【讨论】:

你将如何学习这些东西? data.reduce((r, hobbies, ...o ) 这些类型的语法对我来说是新的。 你可以去destructuring和rest parameters .../spread syntax ...看看。【参考方案2】:

简单的Array.prototype.reduce()Array.prototype.forEach() 联手循环hobbies 的列表,再加上destructuring assignment 语法可以轻松解决问题:

const data = [name:"Sam",ssn:123,age:25,hobbies:[name:"cricket",name:"football"],name:"John",ssn:234,age:25,hobbies:[name:"cricket",name:"football"],name:"Mathew",ssn:345,age:25,hobbies:[name:"cricket",name:"football",name:"carroms"]],
  
      result = data.reduce((r,hobbies, ...userData) => (
        hobbies.forEach((name) => (
          match = r.find((hobby) => hobby == name),
          match ?
          match['person_details'].push(...userData) :
          r.push(hobby:name, person_details: [...userData])
        ))
     , r), [])

console.log(result)
.as-console-wrappermin-height:100%;

【讨论】:

输出应该是一个数组,而不是一个对象【参考方案3】:

改为创建一个索引该爱好的对象。迭代人员时,如果尚不存在,则使用 nameperson_details 数组创建一个新对象,然后推送到 person_details 数组:

const data = [
  
    name: "Sam",
    ssn: 123,
    age: 25,
    hobbies: [ name: "cricket" ,  name: "football" ]
  ,
  
    name: "John",
    ssn: 234,
    age: 25,
    hobbies: [ name: "cricket" ,  name: "football" ]
  ,
  
    name: "Mathew",
    ssn: 345,
    age: 25,
    hobbies: [ name: "cricket" ,  name: "football" , name: "carroms"]
  
];
const peopleByHobbies = ;
for (const  hobbies, ...personData  of data) 
  for (const  name  of hobbies) 
    if (!peopleByHobbies[name]) peopleByHobbies[name] =  name, person_details: [] ;
    peopleByHobbies[name].person_details.push( ...personData );
  

const output = Object.values(peopleByHobbies);
console.log(output);

reduce 可以说是 not the right tool to use 用于这种事情,但如果你想使用它:

const data = [
  
    name: "Sam",
    ssn: 123,
    age: 25,
    hobbies: [ name: "cricket" ,  name: "football" ]
  ,
  
    name: "John",
    ssn: 234,
    age: 25,
    hobbies: [ name: "cricket" ,  name: "football" ]
  ,
  
    name: "Mathew",
    ssn: 345,
    age: 25,
    hobbies: [ name: "cricket" ,  name: "football" , name: "carroms"]
  
];
const peopleByHobbies = data.reduce((peopleByHobbies,  hobbies, ...personData ) => 
  for (const  name  of hobbies) 
    if (!peopleByHobbies[name]) peopleByHobbies[name] =  name, person_details: [] ;
    peopleByHobbies[name].person_details.push( ...personData );
  
  return peopleByHobbies;
, );
const output = Object.values(peopleByHobbies);
console.log(output);

【讨论】:

【参考方案4】:

使用Array#reduce 。您可以使用Spread operator 像这样hobbies,...b 在每次迭代中传递对象

const arr = [ name: "Sam", ssn: 123, age: 25, hobbies: [ name: "cricket" ,  name: "football" ] ,  name: "John", ssn: 234, age: 25, hobbies: [ name: "cricket" ,  name: "football" ] ,  name: "Mathew", ssn: 345, age: 25, hobbies: [ name: "cricket" ,  name: "football" ,  name: "carroms" ]  ];

const res = arr.reduce((acc, hobbies,...b) => 
            hobbies.forEach(i => 
              acc[i.name] = acc[i.name] || 
                name: i.name,
                persional_details: []
              ;
            acc[i.name].persional_details.push(b)
        )
        return acc
      , );

console.log(Object.values(res))

【讨论】:

以上是关于基于嵌套数组重新组合对象数组的主要内容,如果未能解决你的问题,请参考以下文章

MongoDB - 基于嵌套数组的字段值更新数组对象中的字段

如何在 mongodb 聚合中展开嵌套对象数组?

基于数组重新排序对象

对象数组 深度复制,支持对象嵌套数组数组嵌套对象

将对象数组重新格式化为键数组

对象遍历,多层嵌套数组,for in方法对象遍历,map方法数组遍历