【问题标题】:Transform javascript array of object to object with keys and array of values将 javascript 对象数组转换为具有键和值数组的对象
【发布时间】:2020-10-05 08:27:15
【问题描述】:

我有一个需要转换为新对象的对象数组。一些值作为键和值数组。

const data = [
  {
    type: 'user',
    id: 1
  },
  {
    type: 'user',
    id: 2
  },
  {
    type: 'group',
    id: 1
  },
  {
    type: 'group',
    id: 2
  },
  {
    type: 'user',
    id: 3
  },
  {
    type: 'user',
    id: 4
  }
]

想要的结果是

const result = {
  user: [1, 2, 3, 4],
  group: [1, 2]
}

我尝试过使用 reduced,但这不是我所期望的。

const result = data.reduce((acc, { type, ...obj }) => {
  acc[type] = data.map(item => item.id)
  return acc;
}, {})

result = { user: [ 1, 2, 1, 2, 3, 4 ], group: [ 1, 2, 1, 2, 3, 4 ] }

【问题讨论】:

    标签: javascript arrays algorithm object javascript-objects


    【解决方案1】:

    每次迭代,检查accumulate对象是否有类型,如果有,将被迭代元素的id推送到现有数组中,否则初始化数组

    const data = [
      {
        type: "user",
        id: 1,
      },
      {
        type: "user",
        id: 2,
      },
      {
        type: "group",
        id: 1,
      },
      {
        type: "group",
        id: 2,
      },
      {
        type: "user",
        id: 3,
      },
      {
        type: "user",
        id: 4,
      },
    ]
    
    const res = data.reduce((acc, el) => {
      if (acc[el.type]) {
        acc[el.type].push(el.id)
      } else {
        acc[el.type] = [el.id]
      }
    
      return acc
    }, {})
    
    console.log(res)

    【讨论】:

      【解决方案2】:

      除非您使用预定义的 reducer 函数进行函数式编程,否则reduce 通常是一个过于复杂的工具。只需使用循环即可。

      在这种情况下,您将从具有空数组的 usergroup 属性的对象开始,然后使用动态属性名称添加到正确的数组:

      const result = { user: [], group: [] };
      for (const {type, id} of data) {
          result[type].push(id);
      }
      

      现场示例:

      const data = [
        {
          type: 'user',
          id: 1
        },
        {
          type: 'user',
          id: 2
        },
        {
          type: 'group',
          id: 1
        },
        {
          type: 'group',
          id: 2
        },
        {
          type: 'user',
          id: 3
        },
        {
          type: 'user',
          id: 4
        }
      ];
      
      const result = { user: [], group: [] };
      for (const {type, id} of data) {
          result[type].push(id);
      }
      console.log(result);

      如果事先不知道type 的值,请动态添加数组:

      const result = { user: [], group: [] };
      for (const {type, id} of data) {
          if (!result[type]) {
              result[type] = [];
          }
          result[type].push(id);
      }
      

      现场示例:

      const data = [
        {
          type: 'user',
          id: 1
        },
        {
          type: 'user',
          id: 2
        },
        {
          type: 'group',
          id: 1
        },
        {
          type: 'group',
          id: 2
        },
        {
          type: 'user',
          id: 3
        },
        {
          type: 'user',
          id: 4
        }
      ];
      
      const result = { user: [], group: [] };
      for (const {type, id} of data) {
          if (!result[type]) {
              result[type] = [];
          }
          result[type].push(id);
      }
      console.log(result);

      如果你喜欢真的简洁,你可以使用the new ??= operator在数组还没有的时候添加它(对我来说,在这种情况下,它走得太远并且失去了清晰度):

      const result = { user: [], group: [] };
      for (const {type, id} of data) {
          (result[type] ??= []).push(id);
      }
      

      现场示例:

      const data = [
        {
          type: 'user',
          id: 1
        },
        {
          type: 'user',
          id: 2
        },
        {
          type: 'group',
          id: 1
        },
        {
          type: 'group',
          id: 2
        },
        {
          type: 'user',
          id: 3
        },
        {
          type: 'user',
          id: 4
        }
      ];
      
      const result = { user: [], group: [] };
      for (const {type, id} of data) {
          (result[type] ??= []).push(id);
      }
      console.log(result);

      可以将其塞入reduce(因为您可以将任何数组操作塞入reduce),但这样做不会给您带来任何好处.这是第一个使用reduce 而不是循环的:

      const result = data.reduce((acc, {type, id}) => {
          acc[type].push(id);
          return acc;
      }, {user: [], group: []});
      

      const data = [
        {
          type: 'user',
          id: 1
        },
        {
          type: 'user',
          id: 2
        },
        {
          type: 'group',
          id: 1
        },
        {
          type: 'group',
          id: 2
        },
        {
          type: 'user',
          id: 3
        },
        {
          type: 'user',
          id: 4
        }
      ];
      
      const result = data.reduce((acc, {type, id}) => {
          acc[type].push(id);
          return acc;
      }, {user: [], group: []});
      console.log(result);

      【讨论】:

        【解决方案3】:

        您需要检查该属性是否不存在并将id推送给它。

        const
            data = [{ type: 'user', id: 1 }, { type: 'user', id: 2 }, { type: 'group', id: 1 }, { type: 'group', id: 2 }, { type: 'user', id: 3 }, { type: 'user', id: 4 }],
            result = data.reduce((acc, { type, id }) => {
                acc[type] ??= [];
                acc[type].push(id);
                return acc;
            }, {});
        
        console.log(result);

        【讨论】:

        • 紫外线。 ??= 是什么时候出现的。我看到还有||= - 是旧的还是新的?
        • @OriDrori - 它们是在 ES2021 中添加的,here's the (finished) proposal
        【解决方案4】:

        如果累加器上不存在该属性,则添加它,并且如果它确实将id 推入其中:

        const data = [{"type":"user","id":1},{"type":"user","id":2},{"type":"group","id":1},{"type":"group","id":2},{"type":"user","id":3},{"type":"user","id":4}];
        
        const result = data.reduce((acc, { type, id }) => {
          if(!acc[type]) acc[type] = [];
          
          acc[type].push(id);
        
          return acc;
        }, {})
        
        console.log(result)

        【讨论】:

          【解决方案5】:

          这个怎么样?

          groupBy() 的原版版本

          const groupBy = function(xs, key) {
            return xs.reduce(function(rv, x) {
              (rv[x[key]] = rv[x[key]] || []).push(x.id);
              return rv;
            }, {});
          };
          

          您可以通过一个键轻松呼叫组,

          const result = groupBy(data, 'type');
          

          完整代码:

          const groupBy = function(xs, key) {
            return xs.reduce(function(rv, x) {
              (rv[x[key]] = rv[x[key]] || []).push(x.id);
              return rv;
            }, {});
          };
          
          const data = [
            {
              type: 'user',
              id: 1
            },
            {
              type: 'user',
              id: 2
            },
            {
              type: 'group',
              id: 1
            },
            {
              type: 'group',
              id: 2
            },
            {
              type: 'user',
              id: 3
            },
            {
              type: 'user',
              id: 4
            }
          ]
          
          const result = groupBy(data, 'type');
          
          console.log(result); // { group: [1, 2], user: [1, 2, 3, 4] }
          

          参考link

          【讨论】:

            【解决方案6】:

            这是一个使用Object.fromEntries 为结果对象(带有空数组)构建骨架的解决方案。然后一个简单的循环可以填充这些数组,你就完成了:

            let data = [{ type: 'user', id: 1 }, { type: 'user', id: 2 }, { type: 'group', id: 1 }, { type: 'group', id: 2 }, { type: 'user', id: 3 }, { type: 'user', id: 4 }];
            let result = Object.fromEntries(data.map(({type}) => [type, []]));
            for (let {type, id} of data) result[type].push(id);
            
            console.log(result);

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2018-08-07
              • 1970-01-01
              • 1970-01-01
              • 2018-05-10
              • 1970-01-01
              • 2017-09-23
              相关资源
              最近更新 更多