代码之家  ›  专栏  ›  技术社区  ›  Ukasha

使用lodash或ramda变换对象数组

  •  0
  • Ukasha  · 技术社区  · 7 年前

    这是我在查询数据库之后得到的数据结构。

    [
        { name: 'xx1', date: '2017-09-03', value: 49 },
        { name: 'xx2', date: '2017-10-23', value: 67 },
        { name: 'xx2', date: '2017-12-01', value: 70 },
        ...
    ]
    

    我想把它变成:

    [
        { name: 'xx1', data: { '2017-09-03': 49 } },
        { name: 'xx2', data: { '2017-10-23': 67, '2017-12-01': 70 } },
        ...
    ]
    

    为了使用 react-chartkick 是的。

    有人能给我解决这个问题的建议吗?(尤其是洛达斯或拉姆达)

    4 回复  |  直到 7 年前
        1
  •  2
  •   dhilt    7 年前

    我将使用以下方法 reduce find (ES6)方法:

    const data = [
      { name: 'xx1', date: '2017-09-03', value: 49 },
      { name: 'xx2', date: '2017-10-23', value: 67 },
      { name: 'xx2', date: '2017-12-01', value: 70 }
    ];
    
    const result = data.reduce((acc, item) => {
      const found = acc.find(a => a.name === item.name);
      if (found) {
         found.data[item.date] = item.value;
      } else {
        acc.push({
          name: item.name,
          data: {
            [item.date]: item.value
          }
        });
      }
      return acc;
    }, []);
    

    如果你不想要ES6,两种方法都有 lodash 版本: reduce , find .

        2
  •  2
  •   Patrick Roberts Benjamin Gruenbaum    7 年前

    你可以用 Array#reduce() 把它还给 Object.values() 以下内容:

    const data = [
      { name: 'xx1', date: '2017-09-03', value: 49 },
      { name: 'xx2', date: '2017-10-23', value: 67 },
      { name: 'xx2', date: '2017-12-01', value: 70 }
    ]
    const map = data.reduce((acc, { name, date, value }) => {
      if (!(name in acc)) {
        acc[name] = { name, data: {} }
      }
    
      acc[name].data[date] = value
    
      return acc
    }, {})
    const result = Object.values(map)
    
    console.log(result)

    这种方法避免了使用 Array#find() O(n)时间复杂度及其应用 name in acc 检查是否存在 acc[name] 对于访问,这是O(1)时间复杂度,使这种方法O(n)整体。

    相反, the other answer 是o(n 2个 时间复杂度总体而言。

        3
  •  1
  •   CRice    7 年前

    对于使用lodash的解决方案,可以使用 _.map 我是说, _.groupBy ,和 _.merge 实现这一目标的方法。

    我发现使用 _.chain 样式,但如果愿意,可以轻松地将其转换为一组正常的嵌套调用。

    const data = [
        { name: 'xx1', date: '2017-09-03', value: 49 },
        { name: 'xx2', date: '2017-10-23', value: 67 },
        { name: 'xx2', date: '2017-12-01', value: 70 },
    ]
    
    const result = _.chain(data)
      .map(val => ({name: val.name, data: {[val.date]: val.value}})) // convert objects to desired format
      .groupBy("name")                                               // group objects by name
      .map(v => _.merge(...v))                                       // merge objects in each group
      .value();                                                      // done!
      
    console.log(result);
    <script src="https://cdn.jsdelivr.net/npm/lodash@4.17.10/lodash.min.js"></script>
        4
  •  1
  •   Scott Christopher    7 年前

    拉姆达的 R.reduceBy R.groupBy 能帮到你。在下面的例子中 还原比 将数组中的对象按其 name 属性,然后通过将新对象与 R.assoc 是的。剩下的组合 R.toPairs 我是说, R.map R.zipObj 会得到你想要的形状。

    const fn = R.pipe(
      R.reduceBy((res, {date, value}) => R.assoc(date, value, res), {}, R.prop('name')),
      R.toPairs,
      R.map(R.zipObj(['name', 'data']))
    )
    
    const data = [
        { name: 'xx1', date: '2017-09-03', value: 49 },
        { name: 'xx2', date: '2017-10-23', value: 67 },
        { name: 'xx2', date: '2017-12-01', value: 70 }
    ]
    
    console.log(fn(data))
    <script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.min.js"></script>