Удалить дубликаты из массива объектов в JavaScript - PullRequest
260 голосов
/ 08 февраля 2010

У меня есть объект, который содержит массив объектов.

things = new Object();

things.thing = new Array();

things.thing.push({place:"here",name:"stuff"});
things.thing.push({place:"there",name:"morestuff"});
things.thing.push({place:"there",name:"morestuff"});

Мне интересно, как лучше всего удалять дубликаты объектов из массива. Так, например, вещи стали бы ...

{place:"here",name:"stuff"},
{place:"there",name:"morestuff"}

Ответы [ 46 ]

297 голосов
/ 20 апреля 2016

Как насчет магии es6?

things.thing = things.thing.filter((thing, index, self) =>
  index === self.findIndex((t) => (
    t.place === thing.place && t.name === thing.name
  ))
)

Ссылочный URL

Более общее решение будет:

const uniqueArray = things.thing.filter((thing,index) => {
  return index === things.thing.findIndex(obj => {
    return JSON.stringify(obj) === JSON.stringify(thing);
  });
});

Пример Stackblitz

127 голосов
/ 08 февраля 2010

Давайте посмотрим ... примитив будет:

var obj = {};

for ( var i=0, len=things.thing.length; i < len; i++ )
    obj[things.thing[i]['place']] = things.thing[i];

things.thing = new Array();
for ( var key in obj )
    things.thing.push(obj[key]);

Хорошо, я думаю, это должно сработать. Проверьте это, Трэвис.

EDIT
Отредактировал код для правильной ссылки на свойство place (прежнее id).

80 голосов
/ 26 ноября 2014

Если вы можете использовать библиотеки Javascript, такие как underscore или lodash, я рекомендую взглянуть на функцию _.uniq в их библиотеках. От lodash:

_.uniq(array, [isSorted=false], [callback=_.identity], [thisArg])

По сути, вы передаете массив, который здесь является литералом объекта, и передаете атрибут, с которым вы хотите удалить дубликаты в исходном массиве данных, например:

var data = [{'name': 'Amir', 'surname': 'Rahnama'}, {'name': 'Amir', 'surname': 'Stevens'}];
var non_duplidated_data = _.uniq(data, 'name'); 

ОБНОВЛЕНИЕ : Lodash теперь также ввел .uniqBy.

61 голосов
/ 26 июля 2016

У меня было точно такое же требование, чтобы удалить дубликаты объектов в массиве на основе дубликатов в одном поле. Я нашел код здесь: Javascript: удаление дубликатов из массива объектов

Так что в моем примере я удаляю любой объект из массива, который имеет дублирующееся строковое значение licenseNum.

var arrayWithDuplicates = [
    {"type":"LICENSE", "licenseNum": "12345", state:"NV"},
    {"type":"LICENSE", "licenseNum": "A7846", state:"CA"},
    {"type":"LICENSE", "licenseNum": "12345", state:"OR"},
    {"type":"LICENSE", "licenseNum": "10849", state:"CA"},
    {"type":"LICENSE", "licenseNum": "B7037", state:"WA"},
    {"type":"LICENSE", "licenseNum": "12345", state:"NM"}
];

function removeDuplicates(originalArray, prop) {
     var newArray = [];
     var lookupObject  = {};

     for(var i in originalArray) {
        lookupObject[originalArray[i][prop]] = originalArray[i];
     }

     for(i in lookupObject) {
         newArray.push(lookupObject[i]);
     }
      return newArray;
 }

var uniqueArray = removeDuplicates(arrayWithDuplicates, "licenseNum");
console.log("uniqueArray is: " + JSON.stringify(uniqueArray));

Результаты:

uniqueArray - это:

[{"type":"LICENSE","licenseNum":"10849","state":"CA"},
{"type":"LICENSE","licenseNum":"12345","state":"NM"},
{"type":"LICENSE","licenseNum":"A7846","state":"CA"},
{"type":"LICENSE","licenseNum":"B7037","state":"WA"}]
25 голосов
/ 17 июня 2017

Один вкладыш с использованием Set

var things = new Object();

things.thing = new Array();

things.thing.push({place:"here",name:"stuff"});
things.thing.push({place:"there",name:"morestuff"});
things.thing.push({place:"there",name:"morestuff"});

// assign things.thing to myData for brevity
var myData = things.thing;

things.thing = Array.from(new Set(myData.map(JSON.stringify))).map(JSON.parse);

console.log(things.thing)

Пояснение:

  1. new Set(myData.map(JSON.stringify)) создает объект Set с использованием строковых элементов myData.
  2. Установка объекта обеспечит уникальность каждого элемента.
  3. Затем я создаю массив на основе элементов созданного набора, используя Array.from.
  4. Наконец, я использую JSON.parse для преобразования строкового элемента обратно в объект.
22 голосов
/ 08 февраля 2010

Если вы можете ждать устранения дубликатов до тех пор, пока не будут завершены все добавления, типичный подход состоит в том, чтобы сначала отсортировать массив, а затем удалить дубликаты. Сортировка избегает подхода N * N сканирования массива для каждого элемента, когда вы проходите через них.

Функция «устранить дубликаты» обычно называется уникальным или uniq . Некоторые существующие реализации могут объединять два этапа, например, uniq

прототипа

В этом посте есть несколько идей, которые можно попробовать (и некоторые, которых следует избегать :-)) , если в вашей библиотеке еще нет ! Лично я нахожу это самым прямым:

    function unique(a){
        a.sort();
        for(var i = 1; i < a.length; ){
            if(a[i-1] == a[i]){
                a.splice(i, 1);
            } else {
                i++;
            }
        }
        return a;
    }  

    // Provide your own comparison
    function unique(a, compareFunc){
        a.sort( compareFunc );
        for(var i = 1; i < a.length; ){
            if( compareFunc(a[i-1], a[i]) === 0){
                a.splice(i, 1);
            } else {
                i++;
            }
        }
        return a;
    }
21 голосов
/ 26 марта 2016

Вот еще один вариант сделать это с использованием итерационных методов Array, если вам нужно сравнение только по одному полю объекта:

    function uniq(a, param){
        return a.filter(function(item, pos, array){
            return array.map(function(mapItem){ return mapItem[param]; }).indexOf(item[param]) === pos;
        })
    }

    uniq(things.thing, 'place');
15 голосов
/ 29 апреля 2018

один лайнер здесь

let arr = [
  {id:1,name:"sravan ganji"},
  {id:2,name:"anu"},
  {id:4,name:"mammu"},
  {id:3,name:"sanju"},
  {id:3,name:"ram"},
];

console.log(Object.values(arr.reduce((acc,cur)=>Object.assign(acc,{[cur.id]:cur}),{})))
15 голосов
/ 08 февраля 2010

ОБНОВЛЕНО

Я сейчас правильно прочитал вопрос. Это общий способ сделать это: вы передаете функцию, которая проверяет, считаются ли два элемента массива равными. В этом случае сравниваются значения свойств name и place двух сравниваемых объектов.

function arrayContains(arr, val, equals) {
    var i = arr.length;
    while (i--) {
        if ( equals(arr[i], val) ) {
            return true;
        }
    }
    return false;
}

function removeDuplicates(arr, equals) {
    var originalArr = arr.slice(0);
    var i, len, j, val;
    arr.length = 0;

    for (i = 0, len = originalArr.length; i < len; ++i) {
        val = originalArr[i];
        if (!arrayContains(arr, val, equals)) {
            arr.push(val);
        }
    }
}

function thingsEqual(thing1, thing2) {
    return thing1.place === thing2.place
        && thing1.name === thing2.name;
}

removeDuplicates(things.thing, thingsEqual);
13 голосов
/ 11 сентября 2018

Самый простой способ - это использование filter:

var uniq = {}
var arr  = [{"id":"1"},{"id":"1"},{"id":"2"}]
var arrFiltered = arr.filter(obj => !uniq[obj.id] && (uniq[obj.id] = true));
console.log('arrFiltered', arrFiltered)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...