953 Stimmen

Wie entfernt man alle Duplikate aus einem Array von Objekten?

Ich habe ein Objekt, das ein Array von Objekten enthält.

obj = {};

obj.arr = new Array();

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

Ich frage mich, was ist die beste Methode zum Entfernen von doppelten Objekten aus einem Array. Also zum Beispiel, obj.arr werden würde...

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

984voto

Eydrian Punkte 8322

Wie wäre es mit etwas es6 Magie?

obj.arr = obj.arr.filter((value, index, self) =>
  index === self.findIndex((t) => (
    t.place === value.place && t.name === value.name
  ))
)

Referenz-URL

Eine allgemeinere Lösung würde lauten:

const uniqueArray = obj.arr.filter((value, index) => {
  const _value = JSON.stringify(value);
  return index === obj.arr.findIndex(obj => {
    return JSON.stringify(obj) === _value;
  });
});

Die Verwendung der oben genannten Eigenschaftsstrategie anstelle von JSON.stringify :

const isPropValuesEqual = (subject, target, propNames) =>
  propNames.every(propName => subject[propName] === target[propName]);

const getUniqueItemsByProperties = (items, propNames) => 
  items.filter((item, index, array) =>
    index === array.findIndex(foundItem => isPropValuesEqual(foundItem, item, propNames))
  );

Sie können einen Wrapper hinzufügen, wenn Sie wollen, dass die propNames Eigenschaft entweder ein Array oder ein Wert sein:

const getUniqueItemsByProperties = (items, propNames) => {
  const propNamesArray = Array.from(propNames);

  return items.filter((item, index, array) =>
    index === array.findIndex(foundItem => isPropValuesEqual(foundItem, item, propNamesArray))
  );
};

die beide getUniqueItemsByProperties('a') y getUniqueItemsByProperties(['a']);

Stackblitz Beispiel

Erläuterung

  • Machen Sie sich zunächst mit den beiden verwendeten Methoden vertraut:
  • Nehmen Sie als Nächstes Ihre Vorstellung davon, was Ihre beiden Objekte gleich macht, und behalten Sie das im Hinterkopf.
  • Wir können etwas als Duplikat erkennen, wenn es das Kriterium erfüllt, an das wir gerade gedacht haben, aber es befindet sich nicht an der ersten Instanz eines Objekts, das das Kriterium erfüllt.
  • Daher können wir das obige Kriterium verwenden, um festzustellen, ob etwas ein Duplikat ist.

538voto

chickens Punkte 14182

One-Liner mit Filter ( Erhalt der Ordnung )

Einzigartig finden id in einem Array.

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

Wenn die Reihenfolge nicht wichtig ist, sind Kartenlösungen schneller: Lösung mit Karte


Eindeutig durch mehrere Eigenschaften ( place y name )

arr.filter((v,i,a)=>a.findIndex(v2=>['place','name'].every(k=>v2[k] ===v[k]))===i)

Eindeutig für alle Eigenschaften (dies wird bei großen Arrays langsam sein)

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

Behalten Sie das letzte Vorkommen durch Ersetzen findIndex con findLastIndex .

arr.filter((v,i,a)=>a.findLastIndex(v2=>(v2.place === v.place))===i)

326voto

V. Sambor Punkte 10175

Verwendung von ES6+ in einer einzigen Zeile können Sie eine eindeutige Liste von Objekten nach Schlüssel erhalten:

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

Sie kann in eine Funktion eingefügt werden:

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

Hier ein praktisches Beispiel:

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

Wie funktioniert das?

Zunächst wird das Array so umgewandelt, dass es als Eingabe für eine Karte.

arr.map(item => [item[Schlüssel], item]);

was bedeutet, dass jedes Element des Arrays in ein anderes Array mit 2 Elementen umgewandelt wird; die gewählte Taste als erstes Element und die gesamte Ausgangsposition als zweites Element, wird dies als Eintrag bezeichnet (Bsp. Array-Einträge , Karteneinträge ). Und Hier ist das offizielle Dokument mit einem Beispiel, das zeigt, wie man Array-Einträge im Map-Konstruktor hinzufügt.

Beispiel, wenn der Schlüssel Ort :

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

Zweitens übergeben wir dieses geänderte Array an den Map-Konstruktor, und hier geschieht die Magie. Map eliminiert die doppelten Schlüsselwerte und behält nur den zuletzt eingefügten Wert desselben Schlüssels. Hinweis : Map behält die Reihenfolge des Einfügens bei. ( Unterschied zwischen Karte und Objekt prüfen )

new Map(Eintrag Array gerade oben abgebildet)

Drittens verwenden wir die Map-Werte, um die ursprünglichen Elemente abzurufen, aber diesmal ohne Duplikate.

new Map(mappedArr).values()

Und die letzte ist, diese Werte in ein neues Array hinzuzufügen, so dass es als die anfängliche Struktur aussehen kann und das zurückgeben:

return [...new Map(mappedArr).values()]

264voto

leonheess Punkte 9691

Einfache und leistungsfähige Lösung mit besserer Laufzeit als die über 70 Antworten, die es bereits gibt:

const ids = array.map(o => o.id)
const filtered = array.filter(({id}, index) => !ids.includes(id, index + 1))

const arr = [{id: 1, name: 'one'}, {id: 2, name: 'two'}, {id: 1, name: 'one'}]

const ids = arr.map(o => o.id)
const filtered = arr.filter(({id}, index) => !ids.includes(id, index + 1))

console.log(filtered)

Wie es funktioniert:

Array.filter() entfernt alle doppelten Objekte, indem es prüft, ob das zuvor zugeordnete id-array die aktuelle id enthält ( {id} zerstört das Objekt nur in seine id). Um nur tatsächliche Duplikate herauszufiltern, verwendet es Array.includes() der zweite Parameter fromIndex con index + 1 die das aktuelle Objekt und alle vorherigen ignoriert.

Da jede Iteration des filter Callback-Methode nur das Array ab dem aktuellen Index + 1 durchsucht, was die Laufzeit ebenfalls drastisch verkürzt, da nur Objekte geprüft werden, die zuvor nicht gefiltert wurden.

Dies funktioniert natürlich auch für jeden anderen Schlüssel, der nicht id , mehrere oder sogar alle Tasten.

202voto

aefxx Punkte 23877

Eine primitive Methode wäre das:

const obj = {};

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

things.thing = new Array();

 for (const key in obj) { 
   things.thing.push(obj[key]);
}

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X