【问题标题】:Finding unique objects in array在数组中查找唯一对象
【发布时间】:2020-05-13 01:20:31
【问题描述】:

我有一个数组如下:

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 中有没有办法做到这一点?

【问题讨论】:

  • group by 或 .count 可能会对您有所帮助
  • 您的结果在任何正常定义下都不是唯一的,看起来您只是对原始数组进行了重新排序

标签: javascript arrays object lodash


【解决方案1】:

在纯 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']))

【讨论】:

  • 您能解释一下这是如何工作的吗?我喜欢这个实现!
  • 这个工作谢谢
  • @EvanBechtol 添加了一种解释。如果你需要更多问我
【解决方案2】:

这个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}
      ]

在本例中,client 属性不影响唯一性,因此将排除最后一个对象,因为 company 和 date 属性与第一个对象相同。

【讨论】:

  • 哇,这用 lodash 解决了我的问题,非常感谢。从未想过 uniqWith
  • 查看所有 lodash 函数是绝对值得的,主要针对数组、对象和集合,只是为了大致了解该库的功能。
  • 是的!只是另一个问题,如果我只想通过“公司”和“日期”来限制它,我的意思是如果其他具有相同“公司”和“日期”的对象将具有另一个属性,我想认为它是独一无二的。跨度>
【解决方案3】:

使用公司和日期字段对它们进行分组并使用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);

【讨论】:

    【解决方案4】:

    这里在一行中使用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);

    【讨论】:

      猜你喜欢
      • 2020-12-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-10-15
      • 2014-02-09
      • 1970-01-01
      • 2015-12-08
      相关资源
      最近更新 更多