在数组中查找唯一对象

5

我有一个如下的数组:

const arr = [
            {company: 'a', date: '1'},
            {company: 'b', date: '1'},
            {company: 'c', date: '1'},
            {company: 'a', date: '2'},
            {company: 'a', date: '1'},
            {company: 'b', date: '2'},
          ]

我只是想知道如何获取它内部的唯一对象。我尝试使用lodash执行以下命令:

uniqBy(arr, 'date');

但它只返回:
[
  {company: "a", date: "1"},
  {company: "a", date: "2"}
]

我想要类似这个的东西:
[
  {company: "a", date: "1"},
  {company: "a", date: "2"},
  {company: "b", date: "1"},
  {company: "b", date: "2"},
  {company: "c", date: "1"},
]


在lodash或vanilla JS中是否有一种方法可以完成这个操作?

按组分组或使用.count可以帮助您。 - Iria
你的结果在任何正常定义下都不是唯一的,看起来你只是重新排列了原始数组。 - Jamiec
4个回答

7

使用纯JS的 reduce() 函数,我创建了一个函数,它接受对象数组和键数组作为输入,并返回按所有这些键唯一的数组。

算法步骤如下:

  • 首先,我们需要使用 reduce() 创建一个对象。
  • 该对象的 key 将是提供的每个所需键的值,通过 - 连接在一起(我在代码注释中为每个对象提到了 keyString)。
  • 具有相同的keyString的对象表示给定 keys 数组的相同值将自动只出现一次,因为对象不能有重复的键
  • 最后,我们使用 Object.values() 创建一个数组。

const arr = [
            {company: 'a', date: '1'}, //keyString = "a-1"
            {company: 'b', date: '1'}, //keyString = "b-1"
            {company: 'c', date: '1'}, //keyString = "c-1"
            {company: 'a', date: '2'}, //keyString = "a-2"
            {company: 'a', date: '1'}, //keyString = "a-1"
            {company: 'b', date: '2'}, //keyString = "b-2"
            //The item at index 0 and index 4 have same keyString so only a single of them will remain in object.
          ] 

const uniqueBy = (arr, keys) => {
  const obj = arr.reduce((ac, a) => {
    let keyString = keys.map(k => a[k]).join('-');
    ac[keyString] = a;
    return ac;
  }, {});
  return Object.values(obj);
}

console.log(uniqueBy(arr, ['company', 'date']))


你能解释一下这是如何工作的吗?我喜欢这个实现! - Evan Bechtol
这个有效。 - Noel Rosales
1
@EvanBechtol 添加了一种解释。如果您需要更多信息,请问我。 - Maheer Ali

5
这个 lodash 函数组合应该可以实现:
_.uniqWith(arr, _.isEqual);

如果你只想考虑一些属性的组合来保证唯一性,而忽略其他属性,你可以使用uniqBy()函数,并自定义一个用于设置标准的函数。例如:

const arr = [
            {company: 'a', date: '1', clients: 3},
            {company: 'b', date: '1', clients: 2},
            {company: 'c', date: '1', clients: 2},
            {company: 'a', date: '1', clients: 1}
          ]

const uniqArr = _.uniqBy(arr, function(obj){
  return obj.company + obj.date;
});

// => [
       {company: 'a', date: '1', clients: 3},
       {company: 'b', date: '1', clients: 2},
       {company: 'c', date: '1', clients: 2}
      ]

在这个例子中,客户端属性不影响唯一性,因此最后一个对象将被排除,因为公司和日期属性与第一个对象相同。

哇,这个用lodash解决了我的问题,非常感谢。从来没有想过uniqWith。 - Noel Rosales
绝对值得查看所有lodash函数,主要是针对数组、对象和集合,只是为了对库的功能有一个大致的了解。 - Dimitris Papazacharias
是的!又有一个问题,如果我只想通过“公司”和“日期”来限制它,我的意思是如果其他具有相同“公司”和“日期”的对象将具有另一个属性,并且我希望将其视为唯一。 - Noel Rosales

2

使用公司和日期字段对它们进行分组,并使用reduce函数。

const arr = [{
    company: 'a',
    date: '1'
  },
  {
    company: 'b',
    date: '1'
  },
  {
    company: 'c',
    date: '1'
  },
  {
    company: 'a',
    date: '2'
  },
  {
    company: 'a',
    date: '1'
  },
  {
    company: 'b',
    date: '2'
  },
];

const res = Object.values(arr.reduce((acc, curr) => {
  const key = ['company', 'date'].map(x => curr[x]).join('-');

  if (!acc[key]) {
    acc[key] = curr;
  }

  return acc;
}, {}));

console.log(res);


1

使用reduce方法在一行中实现。

const arr = [
  { company: "a", date: "1" },
  { company: "b", date: "1" },
  { company: "c", date: "1" },
  { company: "a", date: "2" },
  { company: "a", date: "1" },
  { company: "b", date: "2" }
];

const updated = Object.values(
  arr.reduce(
    (acc, curr) => ({
      ...acc,
      [`${curr.company}-${curr.date}`]: { ...curr }
    }),
    {}
  )
);

console.log(updated);


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接