如何在 JavaScript 对象数组中查找重复值,并仅输出唯一值?

IT技术 javascript arrays ecmascript-6 javascript-objects
2021-02-10 12:05:16

我正在学习JS。假设我有以下对象数组:

var family = [
  {
    name: "Mike",
    age: 10
  },
  {
    name: "Matt"
    age: 13
  },
  {
    name: "Nancy",
    age: 15
  },
  {
    name: "Adam",
    age: 22
  },
  {
    name: "Jenny",
    age: 85
  },
  {
    name: "Nancy",
    age: 2
  },
  {
    name: "Carl",
    age: 40
  }
];

请注意,Nancy出现了两次(仅更改年龄)。假设我只想输出唯一的名称。如何输出上面的对象数组,没有重复?ES6 的回答非常受欢迎。

相关(找不到在对象上使用的好方法):

编辑这是我尝试过的。它适用于字符串,但我无法弄清楚如何使其适用于对象:

family.reduce((a, b) => {
  if (a.indexOf(b) < 0 ) {
    a.push(b);
  }
  return a;
},[]);
6个回答

您可以在一行Set中结合使用Array#map展开运算符 ...

Map 返回一个包含所有名称的数组,这些名称将进入集合初始值设定项,然后集合中的所有值都返回到一个数组中。

var family = [{ name: "Mike", age: 10 }, { name: "Matt", age: 13 }, { name: "Nancy", age: 15 }, { name: "Adam", age: 22 }, { name: "Jenny", age: 85 }, { name: "Nancy", age: 2 }, { name: "Carl", age: 40 }],
    unique = [...new Set(family.map(a => a.name))];

console.log(unique);

对于过滤并仅返回唯一名称,您可以使用Array#filterwith Set

var family = [{ name: "Mike", age: 10 }, { name: "Matt", age: 13 }, { name: "Nancy", age: 15 }, { name: "Adam", age: 22 }, { name: "Jenny", age: 85 }, { name: "Nancy", age: 2 }, { name: "Carl", age: 40 }],
    unique = family.filter((set => f => !set.has(f.name) && set.add(f.name))(new Set));

console.log(unique);

你的问题我只想输出唯一的名字。? 如果没有,您希望第一个对象还是最后一个对象?
2021-03-18 12:05:16
做得很好。我喜欢你彻底解释的两个选项。
2021-03-24 12:05:16
@jose,这个问题被标记为 ES6,IE11 不支持。您可以使用哈希表代替对象并在那里收集所有名称。
2021-03-24 12:05:16
嗨@Nina Scholz 它工作正常但不工作我 IE11 提供任何其他解决方案
2021-03-30 12:05:16
有没有办法输出我的对象数组而不是这个平面数组?
2021-04-07 12:05:16

解决方案

name将循环外部的事件存储在一个对象中,并过滤是否存在先前的事件。

https://jsfiddle.net/nputptbb/2/

var occurrences = {}

var filteredFamily = family.filter(function(x) {
  if (occurrences[x.name]) {
    return false;
  }
  occurrences[x.name] = true;
  return true;
})

您还可以将此解决方案推广到函数

function filterByProperty(array, propertyName) {
  var occurrences = {}

  return array.filter(function(x) {
    var property = x[propertyName]
    if (occurrences[property]) {
      return false;
    }
    occurrences[property]] = true;
    return true;
  })
}

并像使用它一样

var filteredFamily = filterByProperty(family, 'name')

解释

不要使用 比较对象indexOf,它只使用===对象之间运算符。您当前的答案不起作用的原因是因为===在 JS 中没有深入比较对象,而是比较引用。我的意思是你可以在下面的代码中看到:

var a = { x: 1 }
var b = { x: 1 }

console.log(a === b) // false
console.log(a === a) // true

Equality 会告诉您是否找到了完全相同的对象,但不会告诉您是否找到了具有相同内容的对象。

在这种情况下,您可以比较您的对象,name因为它应该是一个唯一的键。所以obj.name === obj.name代替obj === obj. 此外,影响其运行,而不是它的功能与您的代码的另一个问题是,你使用indexOf你的内部reduceindexOfO(n),这使您的算法变得复杂O(n^2)因此,最好使用具有O(1)查找功能的对象

我非常感谢这个答案——它是跨浏览器的、高性能的且易于阅读。
2021-03-19 12:05:16
这可能是因为你的小提琴写到控制台......正在运行小提琴,看着 o/p,并想知道有什么工作......并没有真正费心先检查代码(并查看其写入控制台)
2021-03-23 12:05:16
因此,如果名称重复,但您希望所有年龄都存储在年龄数组中。所以名字 nacey 和 age 2 已经消失了,但是如果你可以将年龄 2 添加到剩下的对象 nacey 中呢?并且你可以拥有 nacey object age [15, 2]
2021-04-08 12:05:16

这将正常工作。

const result = [1, 2, 2, 3, 3, 3, 3].reduce((x, y) => x.includes(y) ? x : [...x, y], []);

console.log(result);

你能告诉我X做什么和做什么[spreadd x : y ] 吗?还有最后一个空数组[ ]
2021-04-12 12:05:16

我刚刚为 Lodash 用户想到了 2 个简单的方法

鉴于此数组:

let family = [
  {
    name: "Mike",
    age: 10
  },
  {
    name: "Matt",
    age: 13
  },
  {
    name: "Nancy",
    age: 15
  },
  {
    name: "Adam",
    age: 22
  },
  {
    name: "Jenny",
    age: 85
  },
  {
    name: "Nancy",
    age: 2
  },
  {
    name: "Carl",
    age: 40
  }
]

1. 查找重复项:

let duplicatesArr = _.difference(family, _.uniqBy(family, 'name'), 'name')

// duplicatesArr:
// [{ 
//   name: "Nancy", 
//   age: 2 
// }]

2 查找是否有重复项,用于验证目的:

let uniqArr = _.uniqBy(family, 'name')

if (uniqArr.length === family.length) {
    // No duplicates
}

if (uniqArr.length !== family.length) {
    // Has duplicates
}

使用您提到的代码,您可以尝试:

family.filter((item, index, array) => {
  return array.map((mapItem) => mapItem['name']).indexOf(item['name']) === index
})

或者,您可以使用通用函数使其也适用于其他对象数组:

function printUniqueResults (arrayOfObj, key) {
  return arrayOfObj.filter((item, index, array) => {
    return array.map((mapItem) => mapItem[key]).indexOf(item[key]) === index
  })
}

然后只需使用 printUniqueResults(family, 'name')

(小提琴)