Удалить дубликаты из массива объектов в 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 ]

1 голос
/ 06 декабря 2017

Если вы не возражаете против того, чтобы ваш уникальный массив был отсортирован впоследствии, это было бы эффективным решением:

things.thing
  .sort(((a, b) => a.place < b.place)
  .filter((current, index, array) =>
    index === 0 || current.place !== array[index - 1].place)

Таким образом, вам нужно только сравнить текущий элемент с предыдущим элементом в массиве. Сортировка один раз до фильтрации (O(n*log(n))) дешевле, чем поиск дубликата во всем массиве для каждого элемента массива (O(n²)).

1 голос
/ 06 сентября 2018

Продолжаем изучать способы удаления дубликатов из массива объектов ES6: установка thisArg аргумент Array.prototype.filter на new Set предоставляет достойную альтернативу:

const things = [
  {place:"here",name:"stuff"},
  {place:"there",name:"morestuff"},
  {place:"there",name:"morestuff"}
];

const filtered = things.filter(function({place, name}) {

  const key =`${place}${name}`;

  return !this.has(key) && this.add(key);

}, new Set);

console.log(filtered);

Однако он не будет работать с функциями стрелок () =>, поскольку this привязан к их лексической области действия.

1 голос
/ 10 апреля 2019

let myData = [{place:"here",name:"stuff"}, 
 {place:"there",name:"morestuff"},
 {place:"there",name:"morestuff"}];


let q = [...new Map(myData.map(obj => [JSON.stringify(obj), obj])).values()];

console.log(q)

Однострочник с использованием ES6 и new Map().

// assign things.thing to myData
let myData = things.thing;

[...new Map(myData.map(obj => [JSON.stringify(obj), obj])).values()];

подробности: -

  1. Выполнение .map() в списке данных и преобразование каждого отдельного объекта в массив пар [key, value] (длина = 2), первым элементом (ключом) будет версия объекта stringified, а вторым (значение) был бы object сам.
  2. Добавление созданного выше списка массивов к new Map() будет иметь ключ как stringified объект, и любое добавление того же ключа приведет к переопределению уже существующего ключа.
  3. Использование .values() даст MapIterator со всеми значениями на карте (obj в нашем случае)
  4. Наконец, оператор spread ... для выдачи нового массива со значениями из вышеприведенного шага.
1 голос
/ 18 июня 2018

Если вы не хотите указывать список свойств:

function removeDuplicates(myArr) {
  var props = Object.keys(myArr[0])
  return myArr.filter((item, index, self) =>
    index === self.findIndex((t) => (
      props.every(prop => {
        return t[prop] === item[prop]
      })
    ))
  )
}

OBS!Не совместим с IE11.

1 голос
/ 23 мая 2018

Вы слышали о библиотеке Лодаш? Я рекомендую вам эту утилиту, когда вы действительно не хотите применять свою логику к коду и использовать уже существующий код, который оптимизирован и надежен.

Подумайте о создании массива, подобного этому

things.thing.push({place:"utopia",name:"unicorn"});
things.thing.push({place:"jade_palace",name:"po"});
things.thing.push({place:"jade_palace",name:"tigress"});
things.thing.push({place:"utopia",name:"flying_reindeer"});
things.thing.push({place:"panda_village",name:"po"});

Обратите внимание, что если вы хотите сохранить один атрибут уникальным, вы можете сделать это с помощью библиотеки lodash. Здесь вы можете использовать _. UniqBy

.uniqBy (массив, [iteratee = .identity])

Этот метод похож на _. Uniq (который возвращает версию массива без дубликатов, в которой сохраняется только первое вхождение каждого элемента) за исключением того, что он принимает iteratee, который вызывается для каждого элемент в массиве для генерации критерия, по которому вычисляется уникальность.

Так, например, если вы хотите вернуть массив с уникальным атрибутом 'place'

_. UniqBy (вещи. Вещи, «место»)

Точно так же, если вы хотите уникальный атрибут как «имя»

_. UniqBy (things.thing, 'name')

Надеюсь, это поможет.

Ура!

0 голосов
/ 16 марта 2019
const uniqueElements = (arr, fn) => arr.reduce((acc, v) => {
    if (!acc.some(x => fn(v, x))) { acc.push(v); }
    return acc;
}, []);

const stuff = [
    {place:"here",name:"stuff"},
    {place:"there",name:"morestuff"},
    {place:"there",name:"morestuff"},
];

const unique = uniqueElements(stuff, (a,b) => a.place === b.place && a.name === b.name );
//console.log( unique );

[{
    "place": "here",
    "name": "stuff"
  },
  {
    "place": "there",
    "name": "morestuff"
}]
0 голосов
/ 14 марта 2019

Источник

JSFiddle

Это удалит дубликат объекта без передачи ключа.

uniqueArray = a => [...new Set(a.map(o => JSON.stringify(o)))].map(s => JSON.parse(s));

var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }, { 'x': 1, 'y': 2 }];

var unique = uniqueArray(objects);
console.log('Original Object',objects);
console.log('Unique',unique);
uniqueArray = a => [...new Set(a.map(o => JSON.stringify(o)))].map(s => JSON.parse(s));

    var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }, { 'x': 1, 'y': 2 }];

    var unique = uniqueArray(objects);
    console.log(objects);
    console.log(unique);
0 голосов
/ 06 марта 2019

Если вам часто нужно удалять дубликаты объектов из массивов, основанных на определенных полях, возможно, стоит создать функцию distinct(array, predicate), которую можно импортировать из любого места в вашем проекте. Это будет выглядеть как

const things = [{place:"here",name:"stuff"}, ...];
const distinctThings = distinct(things, thing => thing.place);

Отличная функция может использовать любую из реализаций, приведенных во многих хороших ответах выше. Самый простой из них использует findIndex:

const distinct = (items, predicate) => items.filter((uniqueItem, index) =>
    items.findIndex(item =>
        predicate(item) === predicate(uniqueItem)) === index);
0 голосов
/ 05 марта 2019

Что по этому поводу:

function dedupe(arr, compFn){
    let res = [];
    if (!compFn) compFn = (a, b) => { return a === b };
    arr.map(a => {if(!res.find(b => compFn(a, b))) res.push(a)});
    return res;
}
0 голосов
/ 05 марта 2018
str =[
{"item_id":1},
{"item_id":2},
{"item_id":2}
]

obj =[]
for (x in str){
    if(check(str[x].item_id)){
        obj.push(str[x])
    }   
}
function check(id){
    flag=0
    for (y in obj){
        if(obj[y].item_id === id){
            flag =1
        }
    }
    if(flag ==0) return true
    else return false

}
console.log(obj)

str - массив объектов. Существуют объекты, имеющие одинаковое значение (здесь небольшой пример, есть два объекта с одинаковым item_id, равным 2). check (id) - это функция, которая проверяет, существует ли какой-либо объект с таким же item_id или нет. если он существует, вернуть false, в противном случае вернуть true. В соответствии с этим результатом поместите объект в новый массив obj Вывод вышеуказанного кода [{"item_id":1},{"item_id":2}]

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...