Удалить дубликаты из массива объектов в JavaScript

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

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"}

Ответ 1

Посмотрим... примитивным будет:

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]);

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

ИЗМЕНИТЬ
Отредактировал код, чтобы правильно ссылаться на свойство place (прежнее id).

Ответ 2

Как насчет магии 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

Ответ 3

Если вы можете использовать библиотеки Javascript, такие как подчеркивание или 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.

Ответ 4

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

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

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"}]

Ответ 5

Один вкладыш с использованием 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)

Ответ 6

Вот еще один вариант сделать это с помощью методов повторного использования 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');

Ответ 7

Если вы можете подождать, чтобы устранить дубликаты до тех пор, пока после всех дополнений, типичный подход состоит в том, чтобы сначала отсортировать массив, а затем устранить дубликаты. Сортировка позволяет избежать подхода 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;
    }

Ответ 8

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

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}),{})))

Ответ 9

ОБНОВЛЕНО

Теперь я правильно прочитал вопрос. Это общий способ сделать это: вы передаете функцию, которая проверяет, являются ли два элемента массива равными. В этом случае он сравнивает значения свойств 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);

Ответ 10

Самый простой способ - использовать 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)

Ответ 11

Добавить еще один в список. Использование ES6 и Array.reduce с Array.find.
В этом примере фильтрация объектов основана на свойстве guid.

let filtered = array.reduce((accumulator, current) => {
  if (! accumulator.find(({guid}) => guid === current.guid)) {
    accumulator.push(current);
  }
  return accumulator;
}, []);

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

const uniqify = (array, key) => array.reduce((prev, curr) => prev.find(a => a[key] === curr[key]) ? prev : prev.push(curr) && prev, []);

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

const result = uniqify(myArrayOfObjects, 'guid')

Ответ 12

Вы также можете использовать Map:

const dedupThings = Array.from(things.thing.reduce((m, t) => m.set(t.place, t), new Map()).values());

Полный образец:

const 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"});

const dedupThings = Array.from(things.thing.reduce((m, t) => m.set(t.place, t), new Map()).values());

console.log(JSON.stringify(dedupThings, null, 4));

Результат:

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

Ответ 13

Данг, дети, пусть раздавит это, почему бы и нет?

let uniqIds = {}, source = [{id:'a'},{id:'b'},{id:'c'},{id:'b'},{id:'a'},{id:'d'}];
let filtered = source.filter(obj => !uniqIds[obj.id] && (uniqIds[obj.id] = true));
console.log(filtered);
// EXPECTED: [{id:'a'},{id:'b'},{id:'c'},{id:'d'}];

Ответ 14

Решение TypeScript

Это удалит дубликаты объектов, а также сохранит типы объектов.

function removeDuplicateObjects(array: any[]) {
  return [...new Set(array.map(s => JSON.stringify(s)))]
    .map(s => JSON.parse(s));
}

Ответ 15

Самый короткий вкладыш для ES6+

Найти уникальный id в массиве.

arr.filter((v,i,a)=>a.findIndex(t=>(t.id === v.id))===i)

Уникальный по нескольким свойствам (place и name)

arr.filter((v,i,a)=>a.findIndex(t=>(t.place === v.place && t.name===v.name))===i)

Уникальный по всем свойствам

arr.filter((v,i,a)=>a.findIndex(t=>(JSON.stringify(t) === JSON.stringify(v)))===i)

Сохраняй последнее происшествие. Добавьте ломтик и вернитесь к началу, а затем снова вернитесь в конец.

arr.slice().reverse().filter((v,i,a)=>a.findIndex(t=>(t.id === v.id))===i).reverse()

Ответ 16

Используя ES6 в одной строке, вы можете получить уникальный список объектов по ключу:

const unique = [...new Map(arr.map(item => [item[key], item])).values()]

Его можно поместить в функцию и использовать как в следующем примере:

const arr = [
  {place: "here", name: "stuff"},
  {place: "there", name: "morestuff"},
  {place: "a", name: "morestuff"},
  {place: "b", name: "morestuff"},
  {place: "c", name: "morestuff"},
  {place: "here", name: "lol"},
  {place: "there", name: "test"}
]

function getUniqueListBy(arr, key) {
    return [...new Map(arr.map(item => [item[key], item])).values()]
}

const arr1 = getUniqueListBy(arr, 'place')

console.log(arr1)


const arr2 = getUniqueListBy(arr, 'name')

console.log(arr2)

Ответ 17

Другим вариантом будет создание пользовательской функции indexOf, которая сравнивает значения выбранного вами свойства для каждого объекта и обертывает его в функцию уменьшения.

var uniq = redundant_array.reduce(function(a,b){
      function indexOfProperty (a, b){
          for (var i=0;i<a.length;i++){
              if(a[i].property == b.property){
                   return i;
               }
          }
         return -1;
      }

      if (indexOfProperty(a,b) < 0 ) a.push(b);
        return a;
    },[]);

Ответ 18

Учитывая lodash.uniqWith

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

_.uniqWith(objects, _.isEqual);
// => [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }]

Ответ 19

Метод removeDuplicates() принимает массив объектов и возвращает новый массив без дубликатов объектов (на основе свойства id).

const allTests = [
  {name: 'Test1', id: '1'}, 
  {name: 'Test3', id: '3'},
  {name: 'Test2', id: '2'},
  {name: 'Test2', id: '2'},
  {name: 'Test3', id: '3'}
];

function removeDuplicates(array) {
  let uniq = {};
  return array.filter(obj => !uniq[obj.id] && (uniq[obj.id] = true))
}

removeDuplicates(allTests);

Ожидаемый результат:

[
  {name: 'Test1', id: '1'}, 
  {name: 'Test3', id: '3'},
  {name: 'Test2', id: '2'}
];

Сначала мы устанавливаем значение переменной uniq для пустого объекта.

Далее мы фильтруем массив объектов. Фильтр создает новый массив со всеми элементами, которые проходят тест, реализованный предоставленной функцией.

return array.filter(obj => !uniq[obj.id] && (uniq[obj.id] = true));

Выше мы используем функцию короткого замыкания &&. Если левая часть && имеет значение true, то она возвращает значение справа от &&. Если левая сторона ложна, она возвращает то, что находится слева от &&.

Для каждого объекта (obj) мы проверяем uniq для свойства, называемого значением obj.id (в этом случае на первой итерации оно проверяет свойство '1'.) Мы хотим противоположность того, что возвращает (либо true или ложь) именно поэтому мы используем! в! uniq [obj.id]. Если uniq уже имеет свойство id, он возвращает true, что означает ложь (!), Указывающую функции фильтра НЕ добавлять этот объект. Однако, если он не находит свойство obj.id, он возвращает значение false, которое затем оценивается как true (!) И возвращает все справа от && или (uniq [obj.id] = true). Это истинное значение, говорящее методу фильтра добавить obj к возвращаемому массиву, а также добавляет свойство {1: true} в uniq. Это гарантирует, что любой другой экземпляр obj с тем же идентификатором не будет добавлен снова.

Ответ 20

let data = [
  {
    'name': 'Amir',
    'surname': 'Rahnama'
  }, 
  {
    'name': 'Amir',
    'surname': 'Stevens'
  }
];
let non_duplicated_data = _.uniqBy(data, 'name');

Ответ 21

Вот решение для es6, где вы хотите сохранить только последний элемент. Это решение является функциональным и совместимым с Airbnb.

const things = {
  thing: [
    { place: 'here', name: 'stuff' },
    { place: 'there', name: 'morestuff1' },
    { place: 'there', name: 'morestuff2' }, 
  ],
};

const removeDuplicates = (array, key) => {
  return array.reduce((arr, item) => {
    const removed = arr.filter(i => i[key] !== item[key]);
    return [...removed, item];
  }, []);
};

console.log(removeDuplicates(things.thing, 'place'));
// > [{ place: 'here', name: 'stuff' }, { place: 'there', name: 'morestuff2' }]

Ответ 22

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)

Ответ 23

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

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²)).

Ответ 24

Это простой способ удаления двуличности из массива объектов.

Я много работаю с данными, и это полезно для меня.

const data = [{name: 'AAA'}, {name: 'AAA'}, {name: 'BBB'}, {name: 'AAA'}];
function removeDuplicity(datas){
    return datas.filter((item, index,arr)=>{
    const c = arr.map(item=> item.name);
    return  index === c.indexOf(item.name)
  })
}

console.log(removeDuplicity(data))

будет печатать в консоли:

[[object Object] {
name: "AAA"
}, [object Object] {
name: "BBB"
}]

Ответ 25

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

Ответ 26

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

Подумайте о создании такого массива

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 (который возвращает дублируемую версию массива, в которой сохраняется только первое вхождение каждого элемента), за исключением того, что он принимает итерацию, которая вызывается для каждого элемента в массиве, чтобы генерировать критерий, посредством которого вычисляется уникальность.

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

_.uniqBy(things.thing, 'place')

Аналогичным образом, если вы хотите, чтобы уникальный атрибут назывался 'name'

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

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

Ура!

Ответ 27

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

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.

Ответ 28

Продолжаем исследовать способы удаления дубликатов из массива объектов thisArg: установка аргумента Array.prototype.filter для 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);

Ответ 29

ES6 магия в одну строку... читается при этом!

// returns the union of two arrays where duplicate objects with the same 'prop' are removed
const removeDuplicatesWith = (a, b, prop) => a.filter(x => !b.find(y => x[prop] === y[prop]);

Ответ 30

Вот еще один способ найти номер дубликата и удалить его из вашего объекта данных. "dupsCount" - количество копий дубликатов файлов. сначала сортируйте данные и удалите их. это даст вам самое быстрое удаление дубликатов.

  dataArray.sort(function (a, b) {
            var textA = a.name.toUpperCase();
            var textB = b.name.toUpperCase();
            return (textA < textB) ? -1 : (textA > textB) ? 1 : 0;
        });
        for (var i = 0; i < dataArray.length - 1; ) {
            if (dataArray[i].name == dataArray[i + 1].name) {
                dupsCount++;
                dataArray.splice(i, 1);
            } else {
                i++;
            }
        }