首页 > 解决方案 > 如何按子对象对对象列表进行最佳分组?

问题描述

我正在尝试通过它们共享的相似对象对一些 JavaScript 对象进行分组。我可以在 Ruby 中毫不费力地做到这一点,但是对于我的一生(有点尴尬)无法在 JS 中以线性时间解决这个问题。JS 似乎不允许对象文字作为键,至少出于减少的目的。

作为 GraphQL 查询的结果,我有这样的数据:

[
  {
    id: 1,
    name: 'Bob',
    room: {
      id: 5,
      name: 'Kitchen'
    }
  },
  {
    id: 3,
    name: 'Sheila',
    room: {
      id: 5,
      name: 'Kitchen'
    }
  },
  {
    id: 2,
    name: 'Tom',
    room: {
      id: 3,
      name: 'Bathroom'
    }
  }
]

在 UI 中,我们将按它们所在的房间显示对象。我们需要保留对房间本身的引用,否则我们只需按房间属性排序。

我想要做的是将数据重塑成这样的东西:

{
  {id: 5, name: 'Kitchen'}: [{id: 1, name: 'Bob'}, {id: 3, name: 'Sheila'}],
  {id: 3, name: 'Bathroom'}: [{id: 2, name: 'Tom'}]
}

如您所见,这些人按他们所在的房间分组在一起。

也可以做成这样的...

[ 
  { room: {id: 5, name: 'Kitchen'}, people: [{id: 1, name: 'Bob', ...}] }, 
  { room: {id: 3, name: 'Bathroom', people: [{id: 2, name: 'Tom'}]
]

不管结果如何,我们只需要在线性时间按房间分组的人。

我已经尝试过 lodash's groupBy,同时使用mapand reduce,只是做for将列表放在一起的循环等等。我很难过,因为无法使用对象文字(房间)作为哈希索引,我不知道如何通过内部对象有效地分组外部对象。

任何帮助是极大的赞赏。

更新:增加关于尝试以线性时间复杂度来做这件事的清晰度——这个 Ruby 代码的最有效等价物:

h = Hash.new { |h, k| h[k] = [] }
value.each_with_object(h) { |v, m| m[v[:room]] << v }

标签: javascriptgroupinglodashgraphql

解决方案


lodash#groupBy您可以使用和lodash#map收集和转换每个组来解决此问题。此外,我们使用从数组中的每个对象lodash#omit中删除对象。roompersonpeople

var result = _(data)
  .groupBy('room.id')
  .map(people => ({
    room: { ...people[0].room }, 
    people: _.map(people, person => _.omit(person, 'room'))
  })).value();

var data = [
  {
    id: 1,
    name: 'Bob',
    room: {
      id: 5,
      name: 'Kitchen'
    }
  },
  {
    id: 3,
    name: 'Sheila',
    room: {
      id: 5,
      name: 'Kitchen'
    }
  },
  {
    id: 2,
    name: 'Tom',
    room: {
      id: 3,
      name: 'Bathroom'
    }
  }
];

var result = _(data)
  .groupBy('room.id')
  .map(people => ({
    // make sure to create a new room object reference
    // to avoid mutability
    room: { ...people[0].room }, 
    people: _.map(people, person => _.omit(person, 'room'))
  })).value();
  
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.min.js"></script>


推荐阅读