javascript 合并多个数组,从map生成的未知长度

zpf6vheq  于 2023-09-29  发布在  Java
关注(0)|答案(4)|浏览(92)

我有这个起始数组:

const data = [
  {
    roles: [
      {
        name: "one",
      },
      {
        name: "two",
      },
    ],
    name: "Alfa",
  },
  {
    roles: [
      {
        name: "three",
      },
    ],
    name: "Bravo",
  },
  {
    name: "Charlie",
  },
];

我需要为每个名称创建一个对象。如果一个名称有多个角色,则为名称添加一项。
所以,在这个例子中,我需要这个数组:

[
  { name: "Alfa", role: "one" },
  { name: "Alfa", role: "two" },
  { name: "Bravo", role: "three" },
  { name: "Charlie" }
];

这是我写的函数:

const cleanRoles = (data) => {
  const roles = data.map((person) => {
    if (Array.isArray(person.roles) && person.roles.length > 0) {
      return person.roles.map((role) => {
        return {
          name: person.name,
          role: role.name,
        };
      });
    }
    return {
      name: person.name,
    };
  });
  return roles;
};

但我得到

[
  [
    { name: "Alfa", role: "one" },
    { name: "Alfa", role: "two" },
  ],
  [{ name: "Bravo", role: "three" }],
  { name: "Charlie" },
];

我如何重构我的函数以获得我需要的东西?

vsaztqbk

vsaztqbk1#

一个reduce,一个forEach,以及易于阅读的代码...(对吧?)

const data = 
  [ { roles : [ { name: 'one' } , { name: 'two' } ] 
    , name  : 'Alfa'
    } 
  , { roles : [ { name: 'three' } ] 
    , name  : 'Bravo'
    } 
  , { name  : 'Charlie' } 
  ];

const result = data.reduce( (acc, {roles,name}) =>
  {
  if (Array.isArray(roles) && roles.length)
    roles.forEach(({name:role}) => acc.push({name,role}));
  else
    acc.push({name});
  return acc;
  },[]);

console.log( result );
.as-console-wrapper    { max-height: 100% !important;top: 0; }
.as-console-row::after { display: none !important;           }
8wigbo56

8wigbo562#

如果在每个对象中交换nameroles属性,并更统一地写出它们,那么就可以更好地理解所发生的事情。我重新排列了下面的数据结构,使数据看起来更容易阅读。
您可以将其简化为以下内容:将数组中的每个项Map到具有namerole的对象(仅当该项具有roles时)。

const data = [{
  name: "Alfa",        /* 1. name = Alfa      */
  roles: [
    { name: "one" },   /*    - role = one     */
    { name: "two" }    /*    - role = two     */
  ]
}, {
  name: "Bravo",       /* 2. name = Bravo     */
  roles: [
    { name: "three" }  /*    - role = three   */
  ]
}, {
  name: "Charlie"      /* 3. name = Charlie   */
}];

const cleanRoles = (data) =>
  data.flatMap(({ name, roles }) =>
    roles?.length
      ? roles.map(({ name: role }) => ({ name, role }))
      : { name });

console.log(cleanRoles(data));
.as-console-wrapper { top: 0; max-height: 100% !important; }
lmyy7pcs

lmyy7pcs3#

通过将角色Map到新的数组项来减少数据。避免使用.flatMap(),因为它比reducing慢:

const result = data.reduce((r, {name, roles}) => 
  (roles?.length ? roles.forEach(({name: role}) => r.push({name, role})) : r.push({name}), r), []);

console.log(result);
<script>
  const data = [{
      roles: [{
          name: "one",
        },
        {
          name: "two",
        },
      ],
      name: "Alfa",
    },
    {
      roles: [{
        name: "three",
      },],
      name: "Bravo",
    },
    {
      name: "Charlie",
    },
  ];
</script>

具有任意数量属性的通用解决方案:

const result = data.reduce((r, {roles, ...user}) => 
  (roles?.length ? roles.forEach(({name: role}) => r.push({...user, role})) : r.push(user), r), []);

console.log(result);
<script>
  const data = [{
      roles: [{
          name: "one",
        },
        {
          name: "two",
        },
      ],
      name: "Alfa",
    },
    {
      roles: [{
        name: "three",
      },],
      name: "Bravo",
    },
    {
      name: "Charlie",
    },
  ];
</script>
` Cycles: 1000000 / Chrome/117
-----------------------------------------------------------
Alexander                  1.0x  |   31   34   35   38   44
Mister Jojo                1.6x  |   49   49   51   52   56
Robin De Schepper         11.7x  |  363  369  374  385  393
-----------------------------------------------------------
https://github.com/silentmantra/benchmark `
<script benchmark="1000000">

      const data = [{
          roles: [{
              name: "one",
            },
            {
              name: "two",
            },
          ],
          name: "Alfa",
        },
        {
          roles: [{
            name: "three",
          },],
          name: "Bravo",
        },
        {
          name: "Charlie",
        },
      ];
      
// @benchmark Mister Jojo      
data.reduce( (acc, {roles,name},i ) =>
  {
  if (Array.isArray(roles) && roles.length)
roles.forEach(({name:role}) => acc.push({name,role}));
  else
acc.push({name});
  return acc;
  },[]);    
      
// @benchmark Robin De Schepper      
data.flatMap((person) => {
    if (Array.isArray(person.roles) && person.roles.length > 0) {
      return person.roles.map((role) => {
        return {
          name: person.name,
          role: role.name,
        };
      });
    }
    return {
      name: person.name,
    };
  });      
      

// @benchmark Alexander
data.reduce((r, {name, roles}) => 
      (roles?.length ? roles.forEach(({name: role}) => r.push({name, role})) : r.push({name}), r), []);
</script>
<script src="https://cdn.jsdelivr.net/gh/silentmantra/benchmark/loader.js"></script>
eqzww0vc

eqzww0vc4#

flatMap做了map做的事情,但是期望数组作为返回值,并将它们连接到一个大数组中作为输出:

const cleanRoles = (data) =>
  data.flatMap((person) => {
    if (Array.isArray(person.roles) && person.roles.length > 0) {
      return person.roles.map((role) => {
        return {
          name: person.name,
          role: role.name,
        };
      });
    }
    return {
      name: person.name,
    };
  });
console.log(cleanRoles(data));
<script>
  const data = [{
      roles: [{
          name: "one",
        },
        {
          name: "two",
        },
      ],
      name: "Alfa",
    },
    {
      roles: [{
        name: "three",
      }, ],
      name: "Bravo",
    },
    {
      name: "Charlie",
    },
  ];
</script>

相关问题