按嵌套属性对对象进行分组的更优雅的方式

More elegant way to group objects by nested attribute

我正在从第三方获取数据 API,无法预先过滤。我有以下数组:

[
 [
  User1 {
    attr1: 'abc',
    attr2: ['0x1', '0xa']
  },
  User2 {
    attr1: 'def'
    attr2: ['0x1', '0xb']
  }
 ]
 [
  User3 {
    attr1: 'ghi',
    attr2: ['0x1', '0xa']
  },
  User4 {
    attr1: 'jkl',
    attr2: ['0x1', '0xb']
  },
  User5 {
    attr1: 'mno',
    attr2: ['0x1', '0xc']
  } 
 ]
]

目标是获得以下内容。本质上,我想根据 attr2[1] 对用户进行分组,并过滤​​掉没有配对的用户。关键是 attr2[1].

[
 {
   attr2_1: '0xa',
   attrs: [User1, User3]
 },
 {
   attr2_1: '0xb',
   attrs: [User2, User4]
 }
]

我有一个可行的解决方案,但我想知道如何更优雅地解决它。

我按第二个属性对用户进行分组

const usersByParam = _.chain(allUsers)
       .flatten()
       .groupBy(user => user.attr2[1])
       .value()
   

我过滤分组的用户以删除没有配对的条目(示例中的 User5)

const filteredUsers = _.omitBy(usersByParam, (val) => {return val.length < 2})

我通过筛选结果来获取我的用户对象

for (const key in filteredUsers) {
  userArray.push({attr2_1: key, attrs: filteredUsers[key]} as User)
}

它给了我想要的东西,但我确信有更优雅的方法来解决它。

您发布的数据无效JSON。因此,假设它应该是一个对象数组,我在下面的代码中对其进行了修改以反映这一点。

我不确定如何在 lodash 中执行此操作,但您可以使用 vanilla JavaScript 来完成此操作。通过使用 Array.reduce() and Array.filter() 方法,您可以根据需要操作数据。

请参阅下面的代码段。

const data = [{
    User1: {
      attr1: 'abc',
      attr2: ['0x1', '0xa']
    }
  },
  {
    User2: {
      attr1: 'def',
      attr2: ['0x1', '0xb']
    }
  },
  {
    User3: {
      attr1: 'ghi',
      attr2: ['0x1', '0xa']
    }
  },
  {
    User4: {
      attr1: 'jkl',
      attr2: ['0x1', '0xb']
    }
  },
  {
    User5: {
      attr1: 'mno',
      attr2: ['0x1', '0xc']
    }
  }
];

const reduced = Object.values(data.reduce((a, c) => {
  var user = Object.keys(c)[0];
  var key = c[user].attr2[1];
  a[key] ??= {};
  a[key].attr2_1 = key;
  a[key].attrs ??= [];
  a[key].attrs.push(user);
  return a;
}, {})).filter(element => element.attrs.length === 2);

console.log(reduced);

您可以使用 JavaScript:

const data = [{User1: {attr1: 'abc',attr2: ['0x1', '0xa']}},{User2: {attr1: 'def',attr2: ['0x1', '0xb']}},{User3: {attr1: 'ghi',attr2: ['0x1', '0xa']}},{User4: {attr1: 'jkl',attr2: ['0x1', '0xb']}},{User5: {attr1: 'mno',attr2: ['0x1', '0xc']}}]
const result = Object.entries(
    data.reduce((a, c) => {
      const [k] = Object.keys(c)
      a[c[k].attr2[1]] = [...(a[c[k].attr2[1]] || []), k]
      return a
    }, {})
  )
  .filter(([, users]) => users.length > 1)
  .map(([attr2_1, attrs]) => ({ attr2_1, attrs }))

console.log(result)

您的代码已经很优雅了,我只是将 for ... in 替换为 map

const userArray = _.chain(allUsers)
  .flatten()
  .groupBy(user => user.attr2[1])
  .omitBy(val => val.length < 2)
  .map((attrs, attr2_1) => ({ attr2_1, attrs }))
  .value();