如何将具有数组键的对象转换为具有无数组键的分解对象

3
嗨,我有一个学生数组。每个学生可能有多个地址(数组)和多个爱好(数组)。
结构如下:
const studentsList = {
  students: [
    {
      id: '54654',
      name: 'Tony',
      address: [
        {
          location: 'SNG',
          building: 2,
        },
        {
          location: 'LON',
          building: 3,
        },
      ],
      hobbies: [
        {
          name: 'soccer',
          id: 123,
        },
        {
          name: 'music',
          id: 53,
        },
      ],
    },
    {
      id: '505389',
      name: 'Stephen Strange',
      address: [
        {
          location: 'LUX',
          building: 8,
        },
        {
          location: 'HK',
          building: 25,
        },
      ],
      hobbies: [
        {
          name: 'watch tv',
          id: 143,
        },
        {
          name: 'music',
          id: 83,
        },
      ],
    },
    {
      id: '34534389',
      name: 'Wanda Maximoff',
      address: [
        {
          location: 'HKG',
          building: 89,
        },
        {
          location: 'GEN',
          building: 79,
        },
      ],
      hobbies: [
        {
          name: 'reading',
          id: 45,
        },
        {
          name: 'chess',
          id: 37,
        },
      ],
    },
  ],
}

我想将学生列表转换为以下格式

1. 每个学生都有一个兴趣爱好的键,并且每个兴趣爱好变成一个单独的爱好,而不是一个数组

2. 每个学生不再有地址键,但是有位置和建筑键。

如下所示

const studentsList = {
  students: [
    {
      id: '54654',
      name: 'Tony',
      location: 'SNG',
      building: 2,
      hobbies:  {
          name: 'soccer',
          id: 123,
        },
    },
    {
      id: '54654',
      name: 'Tony',
      location: 'LON',
      building: 3,
      hobbies:  {
          name: 'soccer',
          id: 123,
        },
    },
    {
      id: '54654',
      name: 'Tony',
      location: 'SNG',
      building: 2,
      hobbies:  {
          name: 'music',
          id: 53,
        },
    },

    {
      id: '54654',
      name: 'Tony',
      location: 'LON',
      building: 3,
      hobbies:  {
          name: 'music',
          id: 53,
        },
    },



    {
      id: '505389',
      name: 'Stephen Strange',
      location: 'LUX',
      building: 8,
      hobbies: {
          name: 'watch tv',
          id: 143,
        },
    }, 
    {
      id: '505389',
      name: 'Stephen Strange',
      location: 'HK',
      building: 25,
      hobbies: {
          name: 'watch tv',
          id: 143,
        },
    }, 
    {
      id: '505389',
      name: 'Stephen Strange',
      location: 'HK',
      building: 25,
      hobbies: {
          name: 'music',
          id: 83,
        },
    }, 
    {
      id: '505389',
      name: 'Stephen Strange',
      location: 'LUX',
      building: 8,
      hobbies: {
          name: 'music',
          id: 83,
        },
    }, 
    {
      id: '34534389',
      name: 'Wanda Maximoff',
      location: 'HKG',
      building: 89,
      hobbies:{
          name: 'reading',
          id: 45,
        },

   },
   {
      id: '34534389',
      name: 'Wanda Maximoff',
      location: 'GEN',
      building: 79,
      hobbies:{
          name: 'reading',
          id: 45,
        },

   },
   {
      id: '34534389',
      name: 'Wanda Maximoff',
      location: 'HKG',
      building: 89,
      hobbies:{
          name: 'chess',
          id: 37,
        },

   }, 
   {
      id: '34534389',
      name: 'Wanda Maximoff',
      location: 'GEN',
      building: 79,
      hobbies:{
          name: 'chess',
          id: 37,
        },

   }
  ],
}

那会给你什么呢?一个带有数据的对象的增长? - imhvost
3个回答

1
const studentsList = {
  students: [
    {
      id: '54654',
      name: 'Tony',
      address: [
        {
          location: 'SNG',
          building: 2,
        },
        {
          location: 'LON',
          building: 3,
        },
      ],
      hobbies: [
        {
          name: 'soccer',
          id: 123,
        },
        {
          name: 'music',
          id: 53,
        },
      ],
    },
    // ... other student objects ...
  ],
};

const transformedStudentList = {
  students: []
};

studentsList.students.forEach(student => {
  student.address.forEach(address => {
    student.hobbies.forEach(hobby => {
      transformedStudentList.students.push({
        id: student.id,
        name: student.name,
        location: address.location,
        building: address.building,
        hobbies: {
          name: hobby.name,
          id: hobby.id
        }
      });
    });
  });
});

console.log(transformedStudentList);

1
这是工作逻辑:

const studentsList = {
  students: [
    {
      id: "54654",
      name: "Tony",
      address: [
        {
          location: "SNG",
          building: 2,
        },
        {
          location: "LON",
          building: 3,
        },
      ],
      hobbies: [
        {
          name: "soccer",
          id: 123,
        },
        {
          name: "music",
          id: 53,
        },
      ],
    },
    {
      id: "505389",
      name: "Stephen Strange",
      address: [
        {
          location: "LUX",
          building: 8,
        },
        {
          location: "HK",
          building: 25,
        },
      ],
      hobbies: [
        {
          name: "watch tv",
          id: 143,
        },
        {
          name: "music",
          id: 83,
        },
      ],
    },
    {
      id: "34534389",
      name: "Wanda Maximoff",
      address: [
        {
          location: "HKG",
          building: 89,
        },
        {
          location: "GEN",
          building: 79,
        },
      ],
      hobbies: [
        {
          name: "reading",
          id: 45,
        },
        {
          name: "chess",
          id: 37,
        },
      ],
    },
  ],
};

function builder(StudentsList) {
  let arr = StudentsList.students;
  let curr = [];

  //

  for (let elem of arr) {
    let address = elem.address;
    let hobbies = elem.hobbies;

    //if hobbies array is empty the terniary operator logic is used
    for (let itemHobbies of hobbies.length > 0
      ? hobbies
      : [{ name: null, id: null }]) {
      for (let itemAddress of address) {
        let temp = {};
        //
        temp.id = elem.id;
        temp.name = elem.name;
        //
        temp.location = itemAddress.location;
        temp.building = itemAddress.building;
        //handling if hobbies array is empty
        if (itemHobbies && itemHobbies.id == null) temp.hobbies = [];
        else temp.hobbies = itemHobbies;
        //

        curr.push(temp);
      }
    }
  }

  return curr;
}

let result = builder(studentsList);

console.log(result);


1
一些疯狂的函数式方法,使用Array::reduce()Array::forEach()。 基本上,你遍历每个学生的爱好,在循环内部将每个学生的地址添加到一个新的学生项目中,该项目包含当前爱好和学生。

const students = studentsList.students
    .reduce((r, { hobbies, address, ...stud }) =>
        hobbies.forEach(hobby => address.forEach(
            addr => r.push(Object.assign({}, stud, addr, {hobbies: hobby}))
        )) || r,
    []);
  
console.log(JSON.stringify({students}, null, 4));
<script>
const studentsList = {
  students: [
    {
      id: '54654',
      name: 'Tony',
      address: [
        {
          location: 'SNG',
          building: 2,
        },
        {
          location: 'LON',
          building: 3,
        },
      ],
      hobbies: [
        {
          name: 'soccer',
          id: 123,
        },
        {
          name: 'music',
          id: 53,
        },
      ],
    },
    {
      id: '505389',
      name: 'Stephen Strange',
      address: [
        {
          location: 'LUX',
          building: 8,
        },
        {
          location: 'HK',
          building: 25,
        },
      ],
      hobbies: [
        {
          name: 'watch tv',
          id: 143,
        },
        {
          name: 'music',
          id: 83,
        },
      ],
    },
    {
      id: '34534389',
      name: 'Wanda Maximoff',
      address: [
        {
          location: 'HKG',
          building: 89,
        },
        {
          location: 'GEN',
          building: 79,
        },
      ],
      hobbies: [
        {
          name: 'reading',
          id: 45,
        },
        {
          name: 'chess',
          id: 37,
        },
      ],
    },
  ],
}
</script>

OP问为什么要使用Object.assign()而不是扩展语法。嗯,我猜测扩展语法涉及到慢速的扩展参数(作为实现),可能会导致类似于最大调用栈/参数数量达到的问题。
在我们的情况下,剩余语法要慢10倍。

enter image description here

    <script benchmark data-count="30000">
    const studentsList = {
      students: [
        {
          id: '54654',
          name: 'Tony',
          address: [
            {
              location: 'SNG',
              building: 2,
            },
            {
              location: 'LON',
              building: 3,
            },
          ],
          hobbies: [
            {
              name: 'soccer',
              id: 123,
            },
            {
              name: 'music',
              id: 53,
            },
          ],
        },
        {
          id: '505389',
          name: 'Stephen Strange',
          address: [
            {
              location: 'LUX',
              building: 8,
            },
            {
              location: 'HK',
              building: 25,
            },
          ],
          hobbies: [
            {
              name: 'watch tv',
              id: 143,
            },
            {
              name: 'music',
              id: 83,
            },
          ],
        },
        {
          id: '34534389',
          name: 'Wanda Maximoff',
          address: [
            {
              location: 'HKG',
              building: 89,
            },
            {
              location: 'GEN',
              building: 79,
            },
          ],
          hobbies: [
            {
              name: 'reading',
              id: 45,
            },
            {
              name: 'chess',
              id: 37,
            },
          ],
        },
      ],
    }
    
    // @benchmark Object.assign
    studentsList.students
        .reduce((r, { hobbies, address, ...stud }) =>
            hobbies.forEach(hobby => address.forEach(
                addr => r.push(Object.assign({}, stud, addr, {hobbies: hobby}))
            )) || r,
        []);
    
        // @benchmark spread
    studentsList.students
        .reduce((r, { hobbies, address, ...stud }) =>
            hobbies.forEach(hobby => address.forEach(
                addr => r.push({...stud, ...addr, hobbies: hobby})
            )) || r,
        []);
    
    </script>
<script src="https://cdn.jsdelivr.net/gh/silentmantra/benchmark/loader.js"></script>


谢谢,这是迄今为止最干净的一个。 我可以问一下在 console.log(JSON.stringify({students}, null, 4)); 中的 null 和 4 是用来做什么的吗? - user21357723
1
@user21357723 https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify . null - 忽略替换函数, 4 - 使用4个空格进行 JSON 缩进。如果直接在控制台输出而不使用 JSON,你将得到以引用形式显示的产品,而不是对象... - Alexander Nenashev
1
@user21357723 我是一个性能狂人。r.push({ ...stud, ...addr, {hobbies: hobby}})) 运行速度较慢,而 Object.assign() 则非常快速。 - Alexander Nenashev
1
@user21357723 || r 其实不太好,它从回调函数中返回了 r,因为 r.push()undefined。你可以写成 ; return r;,但这需要在函数体中加上 {} 括号,所以我偷懒了一下。 - Alexander Nenashev
@user21357723 这是我的工具 https://github.com/silentmantra/benchmark - Alexander Nenashev
显示剩余3条评论

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