Another approach (also for object/array elements within the array1) could be2:
function chkDuplicates(arr,justCheck){
var len = arr.length, tmp = {}, arrtmp = arr.slice(), dupes = [];
arrtmp.sort();
while(len--){
var val = arrtmp[len];
if (/nul|nan|infini/i.test(String(val))){
val = String(val);
}
if (tmp[JSON.stringify(val)]){
if (justCheck) {return true;}
dupes.push(val);
}
tmp[JSON.stringify(val)] = true;
}
return justCheck ? false : dupes.length ? dupes : null;
}
//usages
chkDuplicates([1,2,3,4,5],true); //=> false
chkDuplicates([1,2,3,4,5,9,10,5,1,2],true); //=> true
chkDuplicates([{a:1,b:2},1,2,3,4,{a:1,b:2},[1,2,3]],true); //=> true
chkDuplicates([null,1,2,3,4,{a:1,b:2},NaN],true); //=> false
chkDuplicates([1,2,3,4,5,1,2]); //=> [1,2]
chkDuplicates([1,2,3,4,5]); //=> null
See also…
1 needs a browser that supports JSON, or a JSON library if not.
2 edit: function can now be used for simple check or to return an array of duplicate values
There are multiple methods available to check if an array contains duplicate values in JavaScript. You can use the indexOf()
method, the Set
object, or iteration to identify repeated items in an array.
Set
Object
Set is a special data structure introduced in ES6 that stores a collection of unique values. Since each value in a Set
has to be unique, passing any duplicate item will be removed automatically:
const numbers = [1, 2, 3, 2, 4, 5, 5, 6];
const unique = Array.from(new Set(numbers));
console.log(unique);
// [ 1, 2, 3, 4, 5, 6 ]
The Array.from() method, we used above, converts the Set
back to an array. This is required because a Set
is not an array. You could also use spread operator if you want for conversion:
const unique = [...new Set(numbers)];
To check if there were duplicate items in the original array, just compare the length of both arrays:
const numbers = [1, 2, 3, 2, 4, 5, 5, 6];
const unique = Array.from(new Set(numbers));
if(numbers.length === unique.length) {
console.log(`Array doesn't contain duplicates.`);
} else {
console.log(`Array contains duplicates.`);
}
// Output: Array contains duplicates.
To find out exactly which elements are duplicates, you could make use of the unique
array above, and remove each item from the original array as shown below:
const numbers = [1, 2, 3, 2, 4, 5, 5, 6];
const set = new Set(numbers);
const duplicates = numbers.filter(item => {
if (set.has(item)) {
set.delete(item);
} else {
return item;
}
});
console.log(duplicates);
// [ 2, 5 ]
indexOf()
Method
In this method, we compare the index of the first occurrence of an element with all the elements in an array. If they do not match, it implies that the element is a duplicate:
const numbers = [1, 2, 3, 2, 4, 5, 5, 6];
const duplicates = numbers.filter((item, index) => index !== numbers.indexOf(item));
console.log(duplicates);
// [ 2, 5 ]
The above solution works perfectly as long as you only want to check if the array contains repeated items. However, the output array may contain duplicate items if those items occur more than twice in the array:
const numbers = [1, 2, 3, 2, 2, 4, 5, 5, 6];
const duplicates = numbers.filter((item, index) => index !== numbers.indexOf(item));
console.log(duplicates);
// [ 2, 2, 5 ]
some()
Method
In JavaScript, the some()
method returns true
if one or more elements pass a certain condition.
Just like the filter()
method, the some()
method iterates over all elements in an array to evaluate the given condition.
In the callback function, we again use the indexOf()
method to compare the current element index with other elements in the array. If both the indexes are the same, it means that the current item is not duplicate:
const numbers = [1, 2, 3, 2, 4, 5, 5, 6];
const isDuplicate = numbers.some((item, index) => index !== numbers.indexOf(item));
if (!isDuplicate) {
console.log(`Array doesn't contain duplicates.`);
} else {
console.log(`Array contains duplicates.`);
}
// Output: Array contains duplicates.
for
Loop
Finally, the last method to find duplicates in an array is to use the for
loop.
Here is an example that compares each element of the array with all other elements of the array to check if two values are the same using nested for loop:
const numbers = [1, 2, 3, 2, 4, 5, 5, 6];
let isDuplicate = false;
// Outer for loop
for (let i = 0; i < numbers.length; i++) {
// Inner for loop
for (let j = 0; j < numbers.length; j++) {
// Skip self comparison
if (i !== j) {
// Check for duplicate
if (numbers[i] === numbers[j]) {
isDuplicate = true;
// Terminate inner loop
break;
}
}
// Terminate outer loop
if (isDuplicate) {
break;
}
}
}
if (!isDuplicate) {
console.log(`Array doesn't contain duplicates.`);
} else {
console.log(`Array contains duplicates.`);
}
// Output: Array contains duplicates.
✌️ Like this article? Follow me on
Twitter
and LinkedIn.
You can also subscribe to
RSS Feed.
В этом посте мы обсудим, как найти все дубликаты в массиве в JavaScript.
1. Использование Array.prototype.indexOf()
функция
Идея состоит в том, чтобы сравнить индекс всех элементов в массиве с индексом их первого появления. Если оба индекса не совпадают ни для одного элемента в массиве, можно сказать, что текущий элемент дублируется. Чтобы вернуть новый массив с дубликатами, используйте filter() метод.
В следующем примере кода показано, как реализовать это с помощью indexOf() метод:
const arr = [ 5, 3, 4, 2, 3, 7, 5, 6 ]; const findDuplicates = arr => arr.filter((item, index) => arr.indexOf(item) !== index) const duplicates = findDuplicates(arr); console.log(duplicates); /* результат: [ 3, 5 ] */ |
Скачать Выполнить код
Приведенное выше решение может привести к дублированию значений на выходе. Чтобы справиться с этим, вы можете преобразовать результат в Set
, в котором хранятся уникальные значения.
function findDuplicates(arr) { const filtered = arr.filter((item, index) => arr.indexOf(item) !== index); return [...new Set(filtered)] } const arr = [ 5, 3, 4, 2, 3, 7, 5, 6 ]; const duplicates = findDuplicates(arr); console.log(duplicates); /* результат: [ 3, 5 ] */ |
Скачать Выполнить код
2. Использование Set.prototype.has()
функция
Кроме того, для повышения производительности вы можете использовать ES6. Установить структуру данных для эффективной фильтрации массива.
Следующее решение находит и возвращает дубликаты, используя has() метод. Это работает, потому что каждое значение в наборе должно быть уникальным.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
function findDuplicates(arr) { const distinct = new Set(arr); // для повышения производительности const filtered = arr.filter(item => { // удаляем элемент из набора при первой же встрече if (distinct.has(item)) { distinct.delete(item); } // возвращаем элемент при последующих встречах else { return item; } }); return [...new Set(filtered)] } const arr = [ 5, 3, 4, 2, 3, 7, 5, 6 ]; const duplicates = findDuplicates(arr); console.log(duplicates); /* результат: [ 3, 5 ] */ |
Скачать Выполнить код
Это все о поиске всех дубликатов в массиве в JavaScript.
Спасибо за чтение.
Пожалуйста, используйте наш онлайн-компилятор размещать код в комментариях, используя C, C++, Java, Python, JavaScript, C#, PHP и многие другие популярные языки программирования.
Как мы? Порекомендуйте нас своим друзьям и помогите нам расти. Удачного кодирования 🙂
I’m learning JS. Supposing I have the below array of objects:
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
}
];
Notice that Nancy is showing up twice (changing only the age). Supposing I want to output only unique names. How do I output the above array of objects, without duplicates? ES6 answers more than welcome.
Related (couldn’t find a good way for usage on objects):
- Remove Duplicates from JavaScript Array
- Easiest way to find duplicate values in a JavaScript array
EDIT Here’s what I tried. It works well with strings but I can’t figure how to make it work with objects:
family.reduce((a, b) => {
if (a.indexOf(b) < 0 ) {
a.push(b);
}
return a;
},[]);
asked Oct 6, 2016 at 0:58
Rico LettermanRico Letterman
6311 gold badge6 silver badges13 bronze badges
6
You could use a Set
in combination with Array#map
and a spread operator ...
in a single line.
Map returns an array with all names, which are going into the set initializer and then all values of the set are returned in an array.
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);
For filtering and return only unique names, you can use Array#filter
with 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);
answered Oct 6, 2016 at 18:19
Nina ScholzNina Scholz
374k25 gold badges344 silver badges386 bronze badges
7
The Solution
Store occurrences of name
external to the loop in an object, and filter if there’s been a previous occurrence.
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;
})
you can also generalize this solution to a function
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;
})
}
and use it like
var filteredFamily = filterByProperty(family, 'name')
Explanation
Don’t compare objects using indexOf
, which only uses the ===
operator between objects. The reason why your current answer doesn’t work is because ===
in JS does not compare the objects deeply, but instead compares the references. What I mean by that you can see in the following code:
var a = { x: 1 }
var b = { x: 1 }
console.log(a === b) // false
console.log(a === a) // true
Equality will tell you if you found the same exact object, but not if you found an object with the same contents.
In this case, you can compare your object on name
since it should be a unique key. So obj.name === obj.name
instead of obj === obj
. Moreover another problem with your code that affects its runtime and not its function is that you use an indexOf
inside of your reduce
. indexOf
is O(n)
, which makes the complexity of your algorithm O(n^2)
. Thus, it’s better to use an object, which has O(1)
lookup.
answered Oct 6, 2016 at 1:14
3
This will work fine.
const result = [1, 2, 2, 3, 3, 3, 3].reduce((x, y) => x.includes(y) ? x : [...x, y], []);
console.log(result);
answered Aug 11, 2018 at 17:10
Divyanshu RawatDivyanshu Rawat
4,2112 gold badges37 silver badges49 bronze badges
1
With the code you mentioned, you can try:
family.filter((item, index, array) => {
return array.map((mapItem) => mapItem['name']).indexOf(item['name']) === index
})
Or you can have a generic function to make it work for other array of objects as well:
function printUniqueResults (arrayOfObj, key) {
return arrayOfObj.filter((item, index, array) => {
return array.map((mapItem) => mapItem[key]).indexOf(item[key]) === index
})
}
and then just use printUniqueResults(family, 'name')
(FIDDLE)
answered Oct 6, 2016 at 18:28
Cezar AugustoCezar Augusto
8,5745 gold badges31 silver badges36 bronze badges
I just thought of 2 simple ways for Lodash users
Given this array:
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. Find duplicates:
let duplicatesArr = _.difference(family, _.uniqBy(family, 'name'), 'name')
// duplicatesArr:
// [{
// name: "Nancy",
// age: 2
// }]
2 Find if there are duplicates, for validation purpose:
let uniqArr = _.uniqBy(family, 'name')
if (uniqArr.length === family.length) {
// No duplicates
}
if (uniqArr.length !== family.length) {
// Has duplicates
}
answered Feb 14, 2019 at 10:23
Simon DragsbækSimon Dragsbæk
2,3373 gold badges30 silver badges53 bronze badges
Since most of the answers won’t have a good performance, i thought i share my take on this:
const arrayWithDuplicateData = [{ id: 5, name: 'Facebook'}, { id: 3, name: 'Twitter' }, { id: 5, name: 'Facebook' }];
const uniqueObj = {};
arrayWithDuplicateData.forEach(i => {
uniqueObj[i.id] = i;
});
const arrayWithoutDuplicates = Object.values(uniqueObj);
We’re leveraging the fact that keys are unique within objects. That means the last duplication item inside the first array, will win over its predecessors. If we’d want to change that, we could flip the array before iterating over it.
Also we’re not bound to use only one property of our object for identifying duplications.
const arrayWithDuplicateData = [{ id: 5, name: 'Facebook'}, { id: 3, name: 'Twitter' }, { id: 5, name: 'Facebook' }];
const uniqueObj = {};
arrayWithDuplicateData.forEach(item => {
uniqueObj[`${item.id}_${item.name}`] = item;
});
const arrayWithoutDuplicates = Object.values(uniqueObj);
Or we could simply add a check, if the uniqueObj already holds a key and if yes, not overwrite it.
Overall this way is not very costly in terms of performance and served me well so far.
answered Mar 23, 2021 at 16:01
I would probably set up some kind of object. Since you’ve said ECMAScript 6, you have access to Set
, but since you want to compare values on your objects, it will take a little more work than that.
An example might look something like this (removed namespace pattern for clarity):
var setOfValues = new Set();
var items = [];
function add(item, valueGetter) {
var value = valueGetter(item);
if (setOfValues.has(value))
return;
setOfValues.add(value);
items.push(item);
}
function addMany(items, valueGetter) {
items.forEach(item => add(item, valueGetter));
}
Use it like this:
var family = [
...
];
addMany(family, item => item.name);
// items will now contain the unique items
Explanation: you need to pull a value from each object as it’s added and decide if it has already been added yet, based on the value you get. It requires a value getter, which is a function that given an item, returns a value (item => item.name
). Then, you only add items whose values haven’t already been seen.
A class implementation:
// Prevents duplicate objects from being added
class ObjectSet {
constructor(key) {
this.key = key;
this.items = [];
this.set = new Set();
}
add(item) {
if (this.set.has(item[this.key])) return;
this.set.add(item[this.key]);
this.items.push(item);
}
addMany(items) {
items.forEach(item => this.add(item));
}
}
var mySet = new ObjectSet('name');
mySet.addMany(family);
console.log(mySet.items);
answered Oct 6, 2016 at 1:40
Dave CousineauDave Cousineau
11.9k8 gold badges61 silver badges78 bronze badges
7
Для нахождения одинаковых элементов можно использовать следующий алгоритм:
- Находим количество вхождений (сколько раз встречается в списке) для каждого элемента
- Выводим только те, у которых количество вхождений больше 1
Алгоритм можно реализовать с помощью цикла:
const numbers = [4, 3, 3, 1, 15, 7, 4, 19, 19]; // исходный массив
const countItems = {}; // здесь будет храниться промежуточный результат
// получаем объект в котором ключ - это элемент массива, а значение - сколько раз встречается элемент в списке
// например так будет выглядеть этот объект после цикла:
// {1: 1, 3: 2, 4: 2, 7: 1, 15: 1, 19: 2}
// 1 встречается в тексте 1 раз, 2 встречается 2 раза, 4 встречается 2 раза и так далее
for (const item of numbers) {
// если элемент уже был, то прибавляем 1, если нет - устанавливаем 1
countItems[item] = countItems[item] ? countItems[item] + 1 : 1;
}
// обрабатываем ключи объекта, отфильтровываем все, что меньше 1
const result = Object.keys(countItems).filter((item) => countItems[item] > 1);
console.dir(result); // => ['3', '4', '19']