Usuń duplikaty z tablicy obiektów w JavaScript


373

Mam obiekt, który zawiera tablicę obiektów.

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

Zastanawiam się, jaka jest najlepsza metoda usuwania zduplikowanych obiektów z tablicy. Na przykład rzeczy. Wszystko stałoby się ...

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

Czy masz na myśli, jak zatrzymać tablicę mieszającą / obiekt z dodaniem tych samych parametrów do tablicy?
Matthew Lock

1
Mathew -> Jeśli łatwiej jest w pierwszej kolejności zapobiec dodawaniu do tablicy duplikatu, zamiast filtrować go później, tak, to też byłoby w porządku.
Travis,

2
Zaskakuje mnie, jak ludzie nazywają swoje zmienne. Czasami myślę, że naprawdę chcą, aby było to niepotrzebnie skomplikowane. Dalej zobaczymy aaaaa.aaaa.push(...):)
dazito

Odpowiedzi:


154

Prymitywną metodą byłoby:

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

15
Nigdy nie powinieneś używać długości w pętli for, ponieważ spowolni to obliczanie jej przy każdej iteracji. Przypisz ją do zmiennej poza pętlą i przekaż zmienną zamiast Things.thing.length.
0v3rth3d4wn

12
@ aefxx Nie do końca rozumiem tę funkcję, jak radzisz sobie z sytuacją, że „miejsce” jest takie samo, ale nazwa jest inna, czy należy to rozważyć jako dup, czy nie?
Kuan

2
Chociaż to działa, nie zajmuje się posortowaną tablicą, ponieważ pobieranie kluczy nigdy nie jest gwarantowane. Więc ostatecznie sortujesz. Załóżmy teraz, że tablica nie została posortowana, ale jej kolejność jest ważna, nie ma sposobu, aby upewnić się, że zamówienie pozostanie nienaruszone
Deepak GM

1
@DeepakGM Masz absolutną rację. Odpowiedź nie zachowa (koniecznie) danego zamówienia. Jeśli jest to wymóg, należy poszukać innego rozwiązania.
aefxx

Jak mogę zmodyfikować powyższe, aby usunąć obiekty z tablicy zawierającej X, a także wyodrębnione?
Ryan Holton

435

Co powiesz na es6magię?

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

Referencyjny adres URL

Bardziej ogólnym rozwiązaniem byłoby:

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

Przykład Stackblitz


81
Można to skrócić do:things.thing = things.thing.filter((thing, index, self) => self.findIndex(t => t.place === thing.place && t.name === thing.name) === index)
Josh Cole

Działa świetnie! var uniqueArrayOfObjects = arrayOfObjects.filter (function (obj, index, self) {return index === self.findIndex (function (t) {return t ['obj-property'] === obj ['obj-property'] });}); Upewnij się, że używasz właściwej składni JS.
Mohamed Salem Lamiri

To jest poprawna składnia JS. Twój nie używa 1) funkcji strzałek grubych 2) niejawnego zwrotu lub 3) notacji kropkowej. Twoja jest składnią ES5. Pozostałe to głównie ES6 (ECMA2015). Wszystkie są ważne w 2017 roku. Zobacz komentarz jaredwilli.
agm1984,

8
@vsync po prostu weź odpowiedź @ BKM i ułóż ją razem, ogólnym rozwiązaniem byłoby: const uniqueArray = arrayOfObjects.filter((object,index) => index === arrayOfObjects.findIndex(obj => JSON.stringify(obj) === JSON.stringify(object))); jsfiddle.net/x9ku0p7L/28
Eydrian

9
Kluczem jest tutaj to, że metoda findIndex () zwraca indeks pierwszego elementu, więc jeśli istnieje drugi pasujący element, nigdy nie zostanie on znaleziony i dodany podczas filtrowania.
Patrzyłem

111

Jeśli możesz korzystać z bibliotek Javascript, takich jak podkreślenie lub lodash, polecam przyjrzeć się _.uniqfunkcji w ich bibliotekach. Od lodash:

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

Zasadniczo przekazujesz tablicę, która tutaj jest literałem obiektu, i przekazujesz atrybut, z którym chcesz usunąć duplikaty w oryginalnej tablicy danych, jak poniżej:

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

AKTUALIZACJA : Lodash teraz również wprowadził .uniqBy.


3
@Praveen Pds: Czy mówiłem coś o podkreśleniu w przykładzie kodu? Powiedziałem, że „lodash” ma tę funkcję, a podkreślenie ma podobne. Przed głosowaniem przeczytaj uważnie odpowiedzi.
ambodi

// Wyświetla listę unikalnych obiektów za pomocą _underscore.js holdingObject = _.uniq (holdingObject, funkcja (item, klucz, nazwa) {return item.name;});
praveenpds

26
Uwaga: teraz musisz użyć uniqByzamiast uniqnp. _.uniqBy(data, 'name')... dokumentacji: lodash.com/docs#uniqBy
drmrbrewer

82

Miałem dokładnie ten sam wymóg, aby usunąć zduplikowane obiekty w tablicy na podstawie duplikatów na jednym polu. Znalazłem kod tutaj: JavaScript: Usuń duplikaty z tablicy obiektów

Tak więc w moim przykładzie usuwam z tablicy dowolny obiekt, który ma zduplikowaną wartość ciągu 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));

Wyniki:

UniqueArray to:

[{"type":"LICENSE","licenseNum":"10849","state":"CA"},
{"type":"LICENSE","licenseNum":"12345","state":"NM"},
{"type":"LICENSE","licenseNum":"A7846","state":"CA"},
{"type":"LICENSE","licenseNum":"B7037","state":"WA"}]

1
Byłoby to bardziej użyteczne, gdyby funkcja mogła również filtrować obiekty „falsy”. for(var i in array) { if(array[i][prop]){ //valid lookupObject[array[i][prop]] = array[i]; } else { console.log('falsy object'); } }
Abdul Sadik Yalcin

Dlaczego nie obniżyć złożoności 0 (n), używając: for (let i in originalArray) { if (lookupObject[originalArray[i]['id']] === undefined) { newArray.push(originalArray[i]); } lookupObject[originalArray[i]['id']] = originalArray[i]; }
Tudor B.

jest to najlepszy sposób, ponieważ ważne jest, aby wiedzieć, co chcesz, aby nie powielać się. Czy można to teraz zrobić za pomocą reduktora dla standardów e6?
Christian Matthew

69

Najkrótsza jedna wkładka do ES6 +

Znajdź unikalne idw tablicy.

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

Unikatowy dzięki wielu właściwościom ( placei name)

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

Unikatowy dla wszystkich właściwości (To będzie wolne dla dużych tablic)

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

Zachowaj ostatnie wystąpienie.

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

2
Magia, to prawdziwa odpowiedź
Luis Contreras,

48

Jedna wkładka przy użyciu zestawu

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)

Wyjaśnienie:

  1. new Set(myData.map(JSON.stringify))tworzy obiekt Set przy użyciu strunowanych elementów myData.
  2. Ustaw obiekt zapewni, że każdy element jest unikalny.
  3. Następnie tworzę tablicę na podstawie elementów tworzonego zestawu za pomocą Array.from.
  4. Na koniec używam JSON.parse, aby przekonwertować element zesznurowany z powrotem na obiekt.

18
problem to {a: 1, b: 2} nie będzie równy {b: 2, a: 1}
PirateApp

2
należy pamiętać, że wystąpiłyby problemy z właściwościami daty
MarkosyanArtur

Ta linia tworzy losowe wartości zerowe z obiektem wiersza, który nie istnieje w oryginalnej tablicy obiektów. Czy możesz mi pomóc?
B1K

46

Używając ES6 + w jednym wierszu, możesz uzyskać unikalną listę obiektów według klucza:

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

Można go włączyć w funkcję:

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

Oto działający przykład:

const arr = [
    {place: "here",  name: "x", other: "other stuff1" },
    {place: "there", name: "x", other: "other stuff2" },
    {place: "here",  name: "y", other: "other stuff4" },
    {place: "here",  name: "z", other: "other stuff5" }
]

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

const arr1 = getUniqueListBy(arr, 'place')

console.log("Unique by place")
console.log(JSON.stringify(arr1))

console.log("\nUnique by name")
const arr2 = getUniqueListBy(arr, 'name')

console.log(JSON.stringify(arr2))

Jak to działa

Najpierw tablica jest odwzorowywana w taki sposób, że może być używana jako dane wejściowe dla mapy.

arr.map (item => [item [key], item]);

co oznacza, że ​​każdy element tablicy zostanie przekształcony w inną tablicę z 2 elementami; wybrany klucz jako pierwszego elementu i całej początkowej pozycji jako drugi element, nazywa wpisu (np. wpisy tablic , wpisy map ). A oto oficjalny dokument z przykładem pokazującym, jak dodawać wpisy tablicy w Konstruktorze map.

Przykład, kiedy kluczem jest miejsce :

[["here", {place: "here",  name: "x", other: "other stuff1" }], ...]

Po drugie, przekazujemy tę zmodyfikowaną tablicę konstruktorowi mapy i oto dzieje się magia. Mapa wyeliminuje zduplikowane wartości kluczy, zachowując tylko ostatnią wstawioną wartość tego samego klucza. Uwaga : Mapa zachowuje kolejność wstawiania. ( sprawdź różnicę między mapą a obiektem )

nowa mapa (tablica wprowadzania właśnie zamapowana powyżej)

Po trzecie, używamy wartości mapy, aby odzyskać oryginalne elementy, ale tym razem bez duplikatów.

nowa mapa (mappedArr). wartości ()

Ostatnim jest dodanie tych wartości do nowej, nowej tablicy, aby mogła wyglądać jak struktura początkowa i zwracać:

return [... nowa mapa (mappedArr) .values ​​()]


To nie odpowiada na pierwotne pytanie, ponieważ jest to wyszukiwanie id. Pytanie wymaga, aby cały obiekt był unikalny we wszystkich dziedzinach, takich jak placeiname
L. Holanda,

Twoja funkcja ES6 wydaje się bardzo zwięzła i praktyczna. Czy możesz to trochę wyjaśnić? Co się dokładnie dzieje? Czy usuwane są pierwsze lub ostatnie duplikaty? A może przypadek, który duplikat zostanie usunięty? To by było pomocne, dzięki.
David Schumann

O ile wiem, tworzona jest mapa z wartością właściwości w miarę, jak klucz jest tworzony. Ale nie jest w 100%, w jaki sposób lub czy zachowana jest kolejność tablicy.
David Schumann

1
Cześć @DavidSchumann, zaktualizuję odpowiedź i wyjaśnię, jak to działa. Ale w przypadku krótkiej odpowiedzi kolejność zostaje zachowana, a pierwsza jest usuwana ... Pomyśl tylko o tym, jak jest wstawiona do mapy ... sprawdza, czy klucz już istnieje, zaktualizuje go, a więc pozostanie ostatni
V , Sambor

30

Oto kolejna opcja, aby to zrobić za pomocą metod iteracyjnych Array, jeśli potrzebujesz porównania tylko przez jedno pole obiektu:

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

Chociaż ma to zamówienie większe niż O (n²), pasuje to do mojego przypadku użycia, ponieważ mój rozmiar tablicy zawsze będzie mniejszy niż 30. Dzięki!
Sterex,

24

jedna wkładka jest tutaj

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


1
Ładne i czyste, jeśli chcesz usunąć obiekty tylko z jedną zduplikowaną wartością, a nie tak czyste dla w pełni zduplikowanych obiektów.
David Barker

22

Jeśli możesz poczekać na wyeliminowanie duplikatów, aż po wszystkich dodatkach, typowym podejściem jest najpierw posortowanie tablicy, a następnie wyeliminowanie duplikatów. Sortowanie pozwala uniknąć podejścia N * N polegającego na skanowaniu tablicy dla każdego elementu podczas ich przechodzenia.

Funkcja „eliminuj duplikaty” jest zwykle nazywana unikalną lub uniq . Niektóre istniejące implementacje mogą łączyć dwa etapy, np . Uniq prototypu

Ten post ma kilka pomysłów do wypróbowania (i niektórych, których należy unikać :-)), jeśli twoja biblioteka jeszcze go nie ma ! Osobiście uważam, że ten jest najprostszy:

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

To nie zadziała dla obiektów ogólnych bez naturalnego porządku sortowania.
Tim Down

To prawda, że ​​dodałem dostarczoną przez użytkownika wersję porównawczą.
maccullt,

Podana przez użytkownika wersja porównawcza nie będzie działać, ponieważ jeśli twoja funkcja porównawcza jest, function(_a,_b){return _a.a===_b.a && _a.b===_b.b;}wówczas tablica nie zostanie posortowana.
graham.reeds

1
To jest niepoprawna funkcja porównania. Od developer.mozilla.org/en/Core_JavaScript_1.5_Reference/… ... funkcja porównaj (a, b) {jeśli (a jest mniejsze niż b według jakiegoś kryterium porządkowania) return -1; jeśli (a jest większe niż b według kryterium porządkowania) zwraca 1; // a musi być równe b return 0; } ...
maccullt,

22

Najprostszym sposobem jest użycie 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)


6
Dobrą praktyką w zakresie przepełnienia stosu jest dodanie wyjaśnienia, dlaczego Twoje rozwiązanie powinno działać, zwłaszcza że twoje jest lepsze niż inne odpowiedzi. Aby uzyskać więcej informacji, przeczytaj Jak odpowiedzieć .
Samuel Liew

To nie odpowiada na pierwotne pytanie, ponieważ jest to wyszukiwanie id. Pytanie wymaga, aby cały obiekt był unikalny we wszystkich dziedzinach, takich jak placeiname
L. Holanda,

16

Jest to ogólny sposób: przekazywanie funkcji sprawdzającej, czy dwa elementy tablicy są równe. W tym przypadku porównuje wartości namei placewłaściwości dwóch porównywanych obiektów.

Odpowiedź ES5

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

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

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

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

removeDuplicates(things, thingsEqual);
console.log(things);

Oryginalna odpowiedź ES3

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

1
Dwa obiekty nie będą równe, nawet jeśli będą miały te same właściwości i wartości.
kennebec

Tak, wiem. Ale słusznie, nie udało mi się poprawnie odczytać pytania: nie zauważyłem, że to obiekty o identycznych właściwościach, których potrzebował, aby usunąć. Zmienię swoją odpowiedź.
Tim Down

1
zamiast podczas przebywania wewnątrz arrayContains- użyj Array.prototype..some method Zwraca true, jeśli jeden z członków tablicy spełnia warunek
MarkosyanArtur

13

Aby dodać jeszcze jeden do listy. Korzystanie z ES6 i Array.reduceprzy pomocy Array.find.
W tym przykładzie filtrowanie obiektów na podstawie guidwłaściwości.

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

Rozszerzenie tej opcji, aby umożliwić wybór właściwości i spakowanie jej w jedną warstwę:

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

Aby z niego skorzystać, przekaż tablicę obiektów i nazwę klucza, który chcesz wyodrębnić jako wartość ciągu:

const result = uniqify(myArrayOfObjects, 'guid')

11

Możesz również użyć Map:

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

Pełna próbka:

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

Wynik:

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

+1, miło, choć trochę więcej wyjaśniam wewnętrzne działanie dedupcji, byłoby dobrze - z jasnej strony rozumiem teraz redukcję: D
MimiEAM

11

Cholera, dzieciaki, zmiażdżmy to, dlaczego nie?

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


To nie odpowiada na pierwotne pytanie, ponieważ jest to wyszukiwanie id. Pytanie wymaga, aby cały obiekt był unikalny we wszystkich dziedzinach, takich jak placeiname
L. Holanda,

Jest to udoskonalenie powyższego uogólnienia problemu. Oryginalny pytanie zostało wysłane 9 lat temu, więc oryginalny plakat prawdopodobnie nie martwi się placei namedzisiaj. Każdy, kto czyta ten wątek, szuka optymalnego sposobu na deduplikację listy obiektów, a jest to kompaktowy sposób na zrobienie tego.
Cliff Hall,

11

Rozwiązanie TypeScript

Spowoduje to usunięcie zduplikowanych obiektów, a także zachowanie typów obiektów.

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

2
to jest świetne i krótkie!
mojjj

I bardzo powolny też ...
L. Holanda,

7

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

Doskonały ! Dziękuję ;-)
DonFabiolas

1
Ani uniq firmy Lodash, ani uniqBy nie pomogły, ale twoje rozwiązanie tak. Dzięki! Podaj jednak źródło kodu, jeśli jest to bezpośrednia kopia. lodash.com/docs/4.17.10#uniqWith
Manu CJ

5

Inną opcją byłoby utworzenie niestandardowej funkcji indexOf, która porównuje wartości wybranej właściwości dla każdego obiektu i zawija ją w funkcji redukcji.

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

okazało się to dla mnie świetne - połączyłem to z lodash.isequalpakietem npm jako lekki komparator obiektów, aby wykonać unikalne filtrowanie macierzy ... np. odrębny zestaw obiektów. Właśnie zamieniłem się if (_.isEqual(a[i], b)) {zamiast szukać @ pojedynczej nieruchomości
SliverNinja - MSFT

5

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)

Jednowarstwowy przy użyciu ES6 i new Map().

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

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

Detale:-

  1. Robiąc .map()na liście danych i konwertując każdy pojedynczy obiekt na [key, value]tablicę par (długość = 2), pierwszy element (klucz) byłby stringifiedwersją obiektu, a drugi (wartość) byłbyobject sam.
  2. Dodanie powyżej utworzonej listy tablic do new Map()miałoby klucz jako stringifiedobiekt, a każde dodanie tego samego klucza spowodowałoby zastąpienie już istniejącego klucza.
  3. Użycie .values()dałoby MapIterator ze wszystkimi wartościami na mapie (obj w naszym przypadku)
  4. Na koniec spread ...operator podaje nową tablicę z wartościami z powyższego kroku.

4

Oto rozwiązanie dla es6, w którym chcesz tylko zatrzymać ostatni przedmiot. To rozwiązanie jest funkcjonalne i zgodne ze stylem 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' }]

Możesz usunąć duplikat, a także możesz usunąć cały duplikat za pomocą tego kodu. Nicea
sg28,

4

removeDuplicates () przyjmuje tablicę obiektów i zwraca nową tablicę bez żadnych zduplikowanych obiektów (na podstawie właściwości 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);

Spodziewany rezultat:

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

Najpierw ustawiamy wartość zmiennej uniq na pusty obiekt.

Następnie filtrujemy przez tablicę obiektów. Filtr tworzy nową tablicę ze wszystkimi elementami, które pomyślnie przejdą test zaimplementowany przez podaną funkcję.

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

Powyżej korzystamy z funkcji zwierania &&. Jeśli lewa strona && ma wartość true, to zwraca wartość po prawej stronie &&. Jeśli lewa strona jest fałszywa, zwraca to, co znajduje się po lewej stronie &&.

Dla każdego obiektu (obj) sprawdzamy uniq pod kątem właściwości o nazwie obj.id (W tym przypadku przy pierwszej iteracji sprawdzałby właściwość „1”). Chcemy, aby było odwrotnie niż to, co zwraca (prawda lub false), dlatego używamy! w! uniq [obj.id]. Jeśli uniq ma już właściwość id, zwraca true, co daje wartość false (!), Informując funkcję filtrującą, aby NIE dodawała tego obj. Jeśli jednak nie znajdzie właściwości obj.id, zwraca false, która następnie zwraca wartość true (!) I zwraca wszystko po prawej stronie && lub (uniq [obj.id] = true). Jest to prawdziwa wartość, która mówi metodzie filter, aby dodała ten obiekt do zwracanej tablicy, a także dodaje właściwość {1: true} do uniq. Dzięki temu żadna inna instancja obj o tym samym identyfikatorze nie zostanie dodana ponownie.


Może wytłumacz swój kod i jak odpowiada na pytanie?
mix3d

Dzięki, mix3d. Dodałem wyjaśnienie.
MarkN

Dzięki za wyjaśnienie tego! To rozwiązanie działa dla mnie i jest podobne do kilku innych opublikowanych tutaj, chociaż nie rozumiem, co się dzieje :)
Tim Molloy

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

9
Dodaj wyjaśnienie do swojego kodu, aby przyszli użytkownicy mogli zrozumieć, co robisz. Dzięki.
Błędy

Twoja odpowiedź zależy od zewnętrznej biblioteki kodów ...
Taylor A. Leach

3

Uważam, że połączenie reducez, JSON.stringifyaby idealnie porównać obiekty i selektywne dodawanie tych, którzy nie są jeszcze w akumulatorze, jest eleganckim sposobem.

Należy pamiętać, że JSON.stringifymoże to stanowić problem z wydajnością w skrajnych przypadkach, gdy tablica zawiera wiele obiektów i są one złożone, ALE przez większość czasu jest to najkrótsza droga do przejścia na IMHO.

var collection= [{a:1},{a:2},{a:1},{a:3}]

var filtered = collection.reduce((filtered, item) => {
  if( !filtered.some(filteredItem => JSON.stringify(filteredItem) == JSON.stringify(item)) )
    filtered.push(item)
  return filtered
}, [])

console.log(filtered)

Inny sposób pisania tego samego (ale mniej wydajnego):

collection.reduce((filtered, item) => 
  filtered.some(filteredItem => 
    JSON.stringify(filteredItem ) == JSON.stringify(item)) 
      ? filtered
      : [...filtered, item]
, [])

ten, który działa dla mnie! Dziękuję Ci!
javascript110899

2

Kontynuacja eksploracji sposobów usuwania duplikatów z tablicy obiektów ES6: ustawienie thisArgargumentu Array.prototype.filterna new Setzapewnia przyzwoitą alternatywę:

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

Jednak nie będzie działać z funkcjami strzałek () =>, ponieważ thisjest to związane z ich zakresem leksykalnym.


2

Magia es6 w jednej linii ... czytelna!

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

2

Proste rozwiązanie z metodami pomocniczymi macierzy ES6 „zmniejsz” i „znajdź”

Działa wydajnie i idealnie dobrze!

"use strict";

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

// the logic is here

function removeDup(something) {
    return something.thing.reduce(function (prev, ele) {
        var found = prev.find(function (fele) {
            return ele.place === fele.place && ele.name === fele.name;
        });
        if (!found) {
            prev.push(ele);
        }
        return prev;
    }, []);
}
console.log(removeDup(things));

Bardzo mi to pomogło, dziękuję
jpisty

1

Jeśli nie masz nic przeciwko posortowaniu unikalnej tablicy, byłoby to skuteczne rozwiązanie:

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

W ten sposób wystarczy porównać bieżący element z poprzednim elementem w tablicy. Sortowanie raz przed filtrowaniem ( O(n*log(n))) jest tańsze niż wyszukiwanie duplikatu w całej tablicy dla każdego elementu tablicy ( O(n²)).


1

Jest to prosty sposób na usunięcie duplikatu z tablicy obiektów.

Dużo pracuję z danymi i jest to dla mnie przydatne.

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

wypisze w konsoli:

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

To rozwiązanie ma na celu usunięcie duplikatów z macierzy statycznej, ale kiedy wpychasz dane z zaplecza do tablicy danych, rozważ użycie zastępowania. Ponieważ w tym przypadku nowa wartość przekazana do tablicy danych zostanie usunięta, a „stara” wartość nadal będzie przechowywana w tablicy danych.
Juraj,

1
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 to tablica obiektów. Istnieją obiekty o tej samej wartości (tutaj mały przykład, są dwa obiekty o tym samym item_id jak 2). check (id) to funkcja, która sprawdza, czy istnieje obiekt o tym samym identyfikatorze elementu. jeśli istnieje, zwróć false, w przeciwnym razie zwróć true. Zgodnie z tym wynikiem wciśnij obiekt do nowej tablicy obj . Wyjście powyższego kodu to [{"item_id":1},{"item_id":2}]


Dodaj opis
Mathews Sunny,

@Billa Czy to w porządku?
Bibin Jaimon

1

Czy słyszałeś o bibliotece Lodash? Polecam to narzędzie, gdy tak naprawdę nie chcesz zastosować swojej logiki do kodu i użyć już obecnego kodu, który jest zoptymalizowany i niezawodny.

Rozważ utworzenie takiej tablicy

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

Zauważ, że jeśli chcesz zachować unikalny atrybut, możesz to zrobić za pomocą biblioteki lodash. Tutaj możesz użyć _.uniqBy

.uniqBy (tablica, [iteratee = .identity])

Ta metoda jest podobna do _.uniq (która zwraca pozbawioną duplikatów wersję tablicy, w której zachowane jest tylko pierwsze wystąpienie każdego elementu), z tym wyjątkiem, że akceptuje iterat, który jest wywoływany dla każdego elementu w tablicy w celu wygenerowania kryterium, według którego wyjątkowość jest obliczana.

Na przykład, jeśli chcesz zwrócić tablicę posiadającą unikalny atrybut „miejsce”

_.uniqBy (Things.thing, „place”)

Podobnie, jeśli chcesz unikalny atrybut jako „nazwa”

_.uniqBy (Things.thing, „name”)

Mam nadzieję że to pomoże.

Twoje zdrowie!

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.