Удаление дубликатов из массива объектов в 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"}
1411   30  

30 ответов:

давайте посмотрим ... примитивным было бы:

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) собственность .

Как насчет некоторых es6 магия?

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

ссылка URL

для интерфейсов это может быть немного рано для реализации, так как многие используемые браузеры все еще не поддерживают функции es6

если вы можете использовать библиотеки Javascript, такие как подчеркивание или лодаш, я рекомендую взглянуть на

у меня было точно такое же требование, чтобы удалить дубликаты объектов в массиве, основанные на дубликатах в одном поле. Я нашел код здесь: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"}]

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

функция "устранить дубликаты" обычно называется уникальный или 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;
    }

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

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

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

обновлено

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

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

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;
    },[]);

вы также можете использовать 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"
    }
]

учитывая 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 }]

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

let arr = [
  {id:1,name:"sravan"},
  {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}),{})))

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

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

вот решение для 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' }]

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

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

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

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

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=.идентичность])

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

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

_.uniqBy (вещи.вещь, 'место')

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

_.uniqBy (вещи.вещь, "имя")

надеюсь, что это помогает.

Ура!

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

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.

другой способ - использовать функцию reduce и иметь новый массив в качестве аккумулятора. Если уже есть thing с тем же именем в массиве аккумулятора, то не добавляйте его туда.

let list = things.thing;
list = list.reduce((accumulator, thing) => {
    if (!accumulator.filter((duplicate) => thing.name === duplicate.name)[0]) {
        accumulator.push(thing);
    }
    return accumulator;
}, []);
thing.things = list;

я добавляю этот ответ, потому что я не смог найти хорошее, читаемое решение es6 (я использую babel для обработки функций стрелок), совместимое с Internet Explorer 11. Проблема в том, что IE11 не имеет Map.values() или Set.values() без полифилл. По той же причине я использовал filter()[0] to получить первый элемент вместо find().

 var testArray= ['a','b','c','d','e','b','c','d'];

 function removeDuplicatesFromArray(arr){

 var obj={};
 var uniqueArr=[];
 for(var i=0;i<arr.length;i++){ 
    if(!obj.hasOwnProperty(arr[i])){
        obj[arr[i]] = arr[i];
        uniqueArr.push(arr[i]);
    }
 }

return uniqueArr;

}
var newArr = removeDuplicatesFromArray(testArray);
console.log(newArr);

Output:- [ 'a', 'b', 'c', 'd', 'e' ]

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, то она возвращает значение справа от &&. Если левая сторона false, она возвращает то, что находится на левой стороне &&.

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

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

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)
var data = [{
    'name': 'Amir',
    'surname': 'Rahnama'
}, {
    'name': 'Amir',
    'surname': 'Stevens'
}];
var non_duplidated_data = _.uniqBy(data, 'name');

вот еще один метод, чтобы найти количество дубликатов и легко удалить его из объекта данных. "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++;
            }
        }

вот решение с использованием новой функции фильтра JavaScript, что довольно легко . Допустим, у вас есть такой массив.

var duplicatesArray = ['AKASH','AKASH','NAVIN','HARISH','NAVIN','HARISH','AKASH','MANJULIKA','AKASH','TAPASWENI','MANJULIKA','HARISH','TAPASWENI','AKASH','MANISH','HARISH','TAPASWENI','MANJULIKA','MANISH'];

функция фильтра позволит вам создать новый массив, используя функцию обратного вызова один раз для каждого элемента в массиве. Таким образом, вы можете настроить уникальный массив следующим образом.

var uniqueArray = duplicatesArray.filter(function(elem, pos) {return duplicatesArray.indexOf(elem) == pos;});

в этом случае Ваш уникальный массив будет проходить через все значения в повторяющемся массиве. Переменная elem представляет значение элемент в массиве (Майк, Джеймс, Джеймс, Алекс), позиция это 0-индексированная позиция в массиве (0,1,2,3...), а также дубликаты.значение indexOf (elem) - это просто индекс первого вхождения этого элемента в исходный массив. Итак, поскольку элемент 'james' дублируется, когда мы проходим через все элементы в duplicatesArray и нажимаем их на uniqueArray, в первый раз, когда мы нажимаем james, наше значение "pos" равно 1, а наш индекс(elem) также равен 1, поэтому Джеймс получает толчок к уникальный случай. Во второй раз, когда мы ударили Джеймса, наше значение " pos " равно 2, а наш indexOf(elem) по-прежнему равен 1 (потому что он находит только первый экземпляр элемента массива), поэтому дубликат не выталкивается. Поэтому наш uniqueArray содержит только уникальные значения.

вот демонстрация вышеуказанной функции.Нажмите здесь для приведенного выше примера функции

Если вам нужен уникальный массив, основанный на нескольких свойствах объекта, вы можете сделать это с помощью map и объединить свойства объекта.

    var hash = array.map(function(element){
        var string = ''
        for (var key in element){
            string += element[key]
        }
        return string
    })
    array = array.filter(function(element, index){
        var string = ''
        for (var key in element){
            string += element[key]
        }
        return hash.indexOf(string) == index
    })

универсальный для любого массива объектов:

/**
* Remove duplicated values without losing information
*/
const removeValues = (items, key) => {
  let tmp = {};

  items.forEach(item => {
    tmp[item[key]] = (!tmp[item[key]]) ? item : Object.assign(tmp[item[key]], item);
  });
  items = [];
  Object.keys(tmp).forEach(key => items.push(tmp[key]));

  return items;
}

надеюсь, что это может помочь кому угодно.

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

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

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

Comments

    Ничего не найдено.