Entfernen Sie Duplikate aus einem Array von Objekten in JavaScript

373

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

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

Ich frage mich, was die beste Methode ist, um doppelte Objekte aus einem Array zu entfernen. So würde zum Beispiel alles ... alles werden ...

{place:"here",name:"stuff"},
{place:"there",name:"morestuff"}
Travis
quelle
Meinen Sie damit, wie Sie eine Hashtabelle / ein Objekt stoppen, wenn einem Array dieselben Parameter hinzugefügt werden?
Matthew Lock
1
Mathew -> Wenn es einfacher ist, zu verhindern, dass ein doppeltes Objekt zum Array hinzugefügt wird, anstatt es später herauszufiltern, wäre das auch in Ordnung.
Travis
2
Es überrascht mich immer wieder, wie Leute ihre Variablen benennen. Manchmal denke ich, dass sie es wirklich unnötig kompliziert machen wollen. Weiter zu sehen wird aaaaa.aaaa.push(...):)
dazito

Antworten:

154

Eine primitive Methode wäre:

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]);
aefxx
quelle
15
Sie sollten niemals die Länge in der for-Schleife verwenden, da dies die Berechnung bei jeder Iteration verlangsamt. Weisen Sie es einer Variablen außerhalb der Schleife zu und übergeben Sie die Variable anstelle der Datei things.thing.length.
0v3rth3d4wn
12
@aefxx Ich verstehe diese Funktion nicht ganz. Wie gehen Sie mit der Situation um, dass der "Ort" gleich ist, der Name jedoch unterschiedlich ist? Sollte dies als dup angesehen werden oder nicht?
Kuan
2
Obwohl dies funktioniert, kümmert es sich nicht um ein sortiertes Array, da das Abrufen von Schlüsseln niemals in der Reihenfolge garantiert ist. Am Ende sortieren Sie es also erneut. Angenommen, das Array wurde nicht sortiert, aber seine Reihenfolge ist wichtig. Sie können auf keinen Fall sicherstellen, dass die Reihenfolge erhalten bleibt
Deepak GM,
1
@DeepakGM Du hast absolut Recht. Die Antwort behält (notwendigerweise) eine bestimmte Reihenfolge nicht bei. Wenn dies erforderlich ist, sollte nach einer anderen Lösung gesucht werden.
Aefxx
Wie kann ich das oben Gesagte ändern, um Objekte aus einem Array zu entfernen, die sowohl X enthalten als auch de-duped sind?
Ryan Holton
435

Wie wäre es mit etwas es6Magie?

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

Referenz-URL

Eine allgemeinere Lösung wäre:

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

Stackblitz Beispiel

Eydrian
quelle
81
Dies kann verkürzt werden zu:things.thing = things.thing.filter((thing, index, self) => self.findIndex(t => t.place === thing.place && t.name === thing.name) === index)
Josh Cole
Funktioniert perfekt! var uniqueArrayOfObjects = arrayOfObjects.filter (Funktion (obj, index, self) {return index === self.findIndex (Funktion (t) {return t ['obj-property'] === obj ['obj-property'] });}); Stellen Sie sicher, dass Sie die richtige JS-Syntax verwenden.
Mohamed Salem Lamiri
Das ist die richtige JS-Syntax. Ihre verwendet nicht 1) Fettpfeilfunktionen 2) implizite Rückgabe oder 3) Punktnotation. Ihre ist ES5-Syntax. Die anderen sind meistens ES6 (ECMA2015). Alle sind 2017 gültig. Siehe den Kommentar von jaredwilli.
agm1984
8
@vsync nehmen Sie einfach die Antwort von @ BKM und setzen Sie sie zusammen, eine generische Lösung wäre: const uniqueArray = arrayOfObjects.filter((object,index) => index === arrayOfObjects.findIndex(obj => JSON.stringify(obj) === JSON.stringify(object))); jsfiddle.net/x9ku0p7L/28
Eydrian
9
Der Schlüssel hier ist, dass die findIndex () -Methode den Index des ersten Elements zurückgibt. Wenn also ein zweites Element übereinstimmt, wird es während des Filters nie gefunden und hinzugefügt. Ich starrte es eine Minute lang an :)
JBaczuk
111

Wenn Sie Javascript-Bibliotheken wie Unterstrich oder lodash verwenden können, empfehle ich, sich die _.uniqFunktion in ihren Bibliotheken anzusehen . Von lodash:

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

Grundsätzlich übergeben Sie das Array, das hier ein Objektliteral ist, und Sie übergeben das Attribut, mit dem Sie Duplikate im ursprünglichen Datenarray entfernen möchten, wie folgt:

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

UPDATE : Lodash hat jetzt auch eine eingeführt .uniqBy.

ambodi
quelle
3
@Praveen Pds: Habe ich im Codebeispiel etwas über Unterstrich gesagt? Ich sagte, 'lodash' hat diese Funktion und der Unterstrich hat ähnliche. Bitte lesen Sie die Antworten sorgfältig durch, bevor Sie abstimmen.
Ambodi
// Listet eindeutige Objekte mit _underscore.js auf. HoldingObject = _.uniq (holdingObject, function (item, key, name) {return item.name;});
Praveenpds
26
Hinweis: Sie müssen jetzt uniqByanstelle von uniqzB _.uniqBy(data, 'name')... Dokumentation verwenden: lodash.com/docs#uniqBy
drmrbrewer
83

Ich hatte genau die gleiche Anforderung, doppelte Objekte in einem Array zu entfernen, basierend auf doppelten Objekten in einem einzelnen Feld. Ich habe den Code hier gefunden: Javascript: Duplikate aus dem Array von Objekten entfernen

In meinem Beispiel entferne ich also jedes Objekt aus dem Array, das einen doppelten Lizenznum-Zeichenfolgenwert hat.

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

Die Ergebnisse:

uniqueArray ist:

[{"type":"LICENSE","licenseNum":"10849","state":"CA"},
{"type":"LICENSE","licenseNum":"12345","state":"NM"},
{"type":"LICENSE","licenseNum":"A7846","state":"CA"},
{"type":"LICENSE","licenseNum":"B7037","state":"WA"}]
James Drinkard
quelle
1
Dies wäre nützlicher, wenn die Funktion auch die "falschen" Objekte filtern könnte. for(var i in array) { if(array[i][prop]){ //valid lookupObject[array[i][prop]] = array[i]; } else { console.log('falsy object'); } }
Abdul Sadik Yalcin
Warum nicht die Komplexität 0 (n) for (let i in originalArray) { if (lookupObject[originalArray[i]['id']] === undefined) { newArray.push(originalArray[i]); } lookupObject[originalArray[i]['id']] = originalArray[i]; }
Tudor B.
Dies ist der beste Weg, da es wichtig ist zu wissen, was es ist, dass Sie nicht dupliziert werden möchten. Kann dies nun durch einen Reduzierer für e6-Standards erfolgen?
Christian Matthew
69

Kürzeste Einzeiler für ES6 +

Finden Sie eindeutige idWerte in einem Array.

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

Einzigartig durch mehrere Eigenschaften ( placeund name)

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

Einzigartig für alle Eigenschaften (Dies ist bei großen Arrays langsam)

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

Behalten Sie das letzte Vorkommen.

arr.slice().reverse().filter((v,i,a)=>a.findIndex(t=>(t.id === v.id))===i).reverse()
Hühner
quelle
2
Magie, das ist die wahre Antwort
Luis Contreras
48

Ein Liner mit 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)

Erläuterung:

  1. new Set(myData.map(JSON.stringify)) erstellt eine Erstellt Set- Objekt mit den stringifizierten myData-Elementen.
  2. Mit dem Objekt festlegen wird sichergestellt, dass jedes Element eindeutig ist.
  3. Dann erstelle ich mit Array.from ein Array basierend auf den Elementen des erstellten Sets.
  4. Schließlich verwende ich JSON.parse, um ein stringifiziertes Element wieder in ein Objekt zu konvertieren.
Mμ.
quelle
18
Das Problem ist, dass {a: 1, b: 2} nicht gleich {b: 2, a: 1} ist
PirateApp
2
Denken Sie daran, dass es Probleme mit
Datumseigenschaften
Diese Zeile erstellt zufällige Nullwerte mit einem Zeilenobjekt, das im ursprünglichen Array von Objekten nicht vorhanden ist. Können Sie bitte helfen?
B1K
46

Mit ES6 + in einer einzelnen Zeile erhalten Sie eine eindeutige Liste von Objekten nach Schlüssel:

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

Es kann in eine Funktion eingefügt werden:

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

Hier ist ein Arbeitsbeispiel:

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 es

Zunächst wird das Array so neu zugeordnet, dass es als Eingabe für eine Karte verwendet werden kann.

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

Dies bedeutet, dass jedes Element des Arrays in ein anderes Array mit 2 Elementen umgewandelt wird. Der ausgewählte Schlüssel als erstes Element und das gesamte Anfangselement als zweites Element wird als Eintrag bezeichnet (z. B. Array-Einträge , Karteneinträge ). Und hier ist das offizielle Dokument mit einem Beispiel, das zeigt, wie Array-Einträge im Map-Konstruktor hinzugefügt werden.

Beispiel , wenn der Schlüssel ist Platz :

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

Zweitens übergeben wir dieses modifizierte Array an den Map-Konstruktor und hier geschieht die Magie. Map entfernt die doppelten Schlüsselwerte und behält nur den zuletzt eingefügten Wert desselben Schlüssels bei. Hinweis : Die Karte behält die Einfügereihenfolge bei. ( Unterschied zwischen Karte und Objekt prüfen )

neue Karte (Eintragsarray oben abgebildet)

Drittens verwenden wir die Kartenwerte, um die Originalelemente abzurufen, diesmal jedoch ohne Duplikate.

neue Map (mappedArr) .values ​​()

Und das letzte ist, diese Werte zu einem neuen Array hinzuzufügen, damit es als ursprüngliche Struktur aussehen und Folgendes zurückgeben kann:

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

V. Sambor
quelle
Dies beantwortet nicht die ursprüngliche Frage, da hier nach einem gesucht wird id. Die Frage erfordert, dass das gesamte Objekt in allen Bereichen wie placeundname
L. Holanda
Ihre ES6-Funktion wirkt sehr präzise und praktisch. Können Sie es etwas näher erläutern? Was genau passiert? Werden erste oder letzte Duplikate entfernt? Oder ist es zufällig, welches Duplikat entfernt wird? Das wäre hilfreich, danke.
David Schumann
Soweit ich das beurteilen kann, wird eine Karte mit dem Eigenschaftswert als Schlüssel erstellt. Es ist jedoch nicht 100% ig, wie oder ob die Reihenfolge des Arrays beibehalten wird.
David Schumann
1
Hallo @DavidSchumann, ich werde die Antwort aktualisieren und erklären, wie es funktioniert. Aber für eine kurze Antwort bleibt die Reihenfolge erhalten und die erste wird entfernt ... Denken Sie nur daran, wie sie in die Karte eingefügt wird ... sie prüft, ob der Schlüssel bereits vorhanden ist, aktualisiert ihn, daher bleibt der letzte erhalten
V. Sambor
30

Hier ist eine weitere Option, um Array-Iterationsmethoden zu verwenden, wenn Sie nur einen Vergleich mit einem Feld eines Objekts benötigen:

    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');
Alex Kobylinski
quelle
Obwohl dies eine Ordnung größer als O (n²) hat, passt dies zu meinem Anwendungsfall, da meine Arraygröße immer kleiner als 30 sein wird. Danke!
Sterex
24

Ein Liner ist hier

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

Sravan Ganji
quelle
1
Schön und sauber, wenn Sie nur Objekte mit einem einzigen doppelten Wert entfernen möchten, nicht so sauber für vollständig duplizierte Objekte.
David Barker
22

Wenn Sie warten können, bis die Duplikate entfernt sind, bis alle Ergänzungen abgeschlossen sind, besteht der typische Ansatz darin, zuerst das Array zu sortieren und dann die Duplikate zu entfernen. Die Sortierung vermeidet den N * N-Ansatz, das Array nach jedem Element zu durchsuchen, während Sie durch es gehen.

Die Funktion "Duplikate entfernen " wird normalerweise als eindeutig oder eindeutig bezeichnet . Einige vorhandene Implementierungen können die beiden Schritte kombinieren, z. B. die Uniq des Prototyps

Dieser Beitrag enthält einige Ideen, die Sie ausprobieren sollten (und einige, die Sie vermeiden sollten :-)), falls Ihre Bibliothek noch keine hat ! Persönlich finde ich das am einfachsten:

    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;
    }
maccullt
quelle
Das funktioniert nicht für generische Objekte ohne eine natürliche Sortierreihenfolge.
Tim Down
Richtig, ich habe eine vom Benutzer bereitgestellte Vergleichsversion hinzugefügt.
Maccullt
Ihre vom Benutzer bereitgestellte Vergleichsversion funktioniert nicht, da function(_a,_b){return _a.a===_b.a && _a.b===_b.b;}das Array nicht sortiert wird, wenn Ihre Vergleichsfunktion aktiviert ist .
Graham.reeds
1
Das ist eine ungültige Vergleichsfunktion. Von developer.mozilla.org/en/Core_JavaScript_1.5_Reference/… ... Funktion vergleiche (a, b) {if (a ist nach einem Ordnungskriterium kleiner als b) return -1; wenn (a nach dem Ordnungskriterium größer als b ist) return 1; // a muss gleich b sein return 0; } ...
Maccullt
22

Der einfachste Weg ist die Verwendung 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)

alex dykyі
quelle
6
Bei Stack Overflow empfiehlt es sich, eine Erklärung hinzuzufügen, warum Ihre Lösung funktionieren sollte, insbesondere, wie Ihre Lösung besser ist als die anderen Antworten. Weitere Informationen finden Sie unter Beantworten .
Samuel Liew
Dies beantwortet nicht die ursprüngliche Frage, da hier nach einem gesucht wird id. Die Frage erfordert, dass das gesamte Objekt in allen Bereichen wie placeundname
L. Holanda
17

Dies ist eine generische Methode: Sie übergeben eine Funktion, die prüft, ob zwei Elemente eines Arrays als gleich angesehen werden. In diesem Fall werden die Werte von nameund verglichenplace Eigenschaften der beiden verglichenen Objekte verglichen.

ES5 Antwort

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

Ursprüngliche ES3-Antwort

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);
Tim Down
quelle
1
Zwei Objekte werden nicht gleich bewertet, selbst wenn sie dieselben Eigenschaften und Werte haben.
kennebec
Ja, ich weiß. Aber fairerweise habe ich die Frage nicht richtig gelesen: Ich hatte nicht bemerkt, dass es Objekte mit identischen Eigenschaften waren, die er aussortieren musste. Ich werde meine Antwort bearbeiten.
Tim Down
1
statt in arrayContains- use Array.prototype..some method Gibt true zurück, wenn eines der Array-Mitglieder die Bedingung erfüllt
MarkosyanArtur
13

Hinzufügen eines weiteren zur Liste. Mit ES6 und Array.reducemit Array.find.
In diesem Beispiel werden Objekte basierend auf einer guidEigenschaft gefiltert.

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

Erweitern Sie diese, um die Auswahl einer Eigenschaft zu ermöglichen und sie zu einem Einzeiler zu komprimieren:

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

Um es zu verwenden, übergeben Sie ein Array von Objekten und den Namen des Schlüssels, den Sie als Zeichenfolgenwert entfernen möchten:

const result = uniqify(myArrayOfObjects, 'guid')
Pete B.
quelle
11

Sie können auch Folgendes verwenden Map:

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

Vollständige Probe:

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

Ergebnis:

[
    {
        "place": "here",
        "name": "stuff"
    },
    {
        "place": "there",
        "name": "morestuff"
    }
]
Pragmateek
quelle
+1, schön, ein bisschen mehr zu erklären, wäre das Innenleben von dedupThings gut - auf der positiven Seite verstehe ich jetzt reduzieren: D
MimiEAM
11

Verdammt, Kinder, lasst uns dieses Ding zerquetschen, warum nicht wir?

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

Cliff Hall
quelle
Dies beantwortet nicht die ursprüngliche Frage, da hier nach einem gesucht wird id. Die Frage erfordert, dass das gesamte Objekt in allen Bereichen wie placeundname
L. Holanda
Dies ist eine Verfeinerung einer obigen Verallgemeinerung des Problems. Die ursprüngliche Frage wurde vor 9 Jahren gestellt, daher macht sich das ursprüngliche Poster wahrscheinlich keine Sorgen placeund nameheute. Jeder, der diesen Thread liest, sucht nach einer optimalen Methode, um eine Liste von Objekten zu erstellen, und dies ist eine kompakte Methode, um dies zu tun.
Cliff Hall
11

Eine TypeScript-Lösung

Dadurch werden doppelte Objekte entfernt und die Objekttypen werden beibehalten.

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

quelle
2
das ist toll und kurz!
Mojjj
Und super langsam auch ...
L. Holanda
7

In Anbetracht 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 }]
Justin
quelle
Perfekt ! Vielen Dank
;-)
1
Weder lodashs Uniq noch UniqBy haben es geschafft, aber Ihre Lösung hat es geschafft. Vielen Dank! Bitte geben Sie jedoch die Quelle Ihres Codes an, wenn es sich um eine direkte Kopie handelt. lodash.com/docs/4.17.10#uniqWith
Manu CJ
5

Eine andere Option wäre, eine benutzerdefinierte indexOf-Funktion zu erstellen, die die Werte der von Ihnen ausgewählten Eigenschaft für jedes Objekt vergleicht und diese in eine Reduzierungsfunktion einschließt.

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;
    },[]);
ZeroSum
quelle
Das hat für mich großartig geklappt - ich habe dies mit dem lodash.isequalnpm-Paket als leichtgewichtigen Objektkomparator kombiniert, um eine einzigartige Array-Filterung durchzuführen ... z. B. ein bestimmtes Array von Objekten. Einfach eingetauscht, if (_.isEqual(a[i], b)) {anstatt nach einer einzelnen Immobilie zu suchen
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)

Einzeiler mit ES6 und new Map().

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

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

Einzelheiten:-

  1. Wenn Sie .map()die Datenliste bearbeiten und jedes einzelne Objekt in ein [key, value]Paararray (Länge = 2) konvertieren , ist das erste Element (Schlüssel) die stringifiedVersion des Objekts und das zweite (Wert) eineobject Selbst.
  2. Das Hinzufügen der oben erstellten Array-Liste zu new Map()würde den Schlüssel als habenstringified Objekt haben, und das derselben Schlüssel würde dazu führen, dass der bereits vorhandene Schlüssel überschrieben wird.
  3. Die Verwendung .values()würde MapIterator mit allen Werten in einer Map geben (obj in unserem Fall)
  4. Schließlich spread ...Operator, um neues Array mit Werten aus dem obigen Schritt zu geben.
Savan Akbari
quelle
4

Hier ist eine Lösung für es6, bei der Sie nur das letzte Element behalten möchten. Diese Lösung ist funktional und Airbnb-konform.

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' }]
Micah
quelle
Sie können das Duplikat entfernen und Sie können auch alle Duplikate mit diesem Code entfernen. Nizza
sg28
4

removeDuplicates () nimmt ein Array von Objekten auf und gibt ein neues Array ohne doppelte Objekte zurück (basierend auf der id-Eigenschaft).

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

Erwartetes Ergebnis:

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

Zuerst setzen wir den Wert der Variablen uniq auf ein leeres Objekt.

Als nächstes filtern wir durch das Array von Objekten. Filter erstellt ein neues Array mit allen Elementen, die den von der bereitgestellten Funktion implementierten Test bestehen.

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

Oben verwenden wir die Kurzschlussfunktion von &&. Wenn die linke Seite des && als wahr ausgewertet wird, wird der Wert rechts vom && zurückgegeben. Wenn die linke Seite falsch ist, wird zurückgegeben, was sich auf der linken Seite des && befindet.

Für jedes Objekt (obj) überprüfen wir uniq auf eine Eigenschaft mit dem Namen obj.id (In diesem Fall wird bei der ersten Iteration nach der Eigenschaft '1' gesucht.) Wir möchten das Gegenteil von dem, was es zurückgibt (entweder true) oder falsch) weshalb wir das! in! uniq [obj.id]. Wenn uniq bereits über die Eigenschaft id verfügt, wird true zurückgegeben, was zu false (!) Wertet und der Filterfunktion mitteilt, dass dieses Objekt NICHT hinzugefügt werden soll. Wenn die Eigenschaft obj.id jedoch nicht gefunden wird, wird false zurückgegeben, was dann als true (!) Auswertet und alles rechts von && oder (uniq [obj.id] = true) zurückgibt. Dies ist ein wahrheitsgemäßer Wert, der die Filtermethode anweist, dieses Objekt zum zurückgegebenen Array hinzuzufügen, und die Eigenschaft {1: true} zu uniq hinzufügt. Dadurch wird sichergestellt, dass keine andere Objektinstanz mit derselben ID erneut hinzugefügt wird.

MarkN
quelle
Erklären Sie vielleicht Ihren Code und wie er die Frage beantwortet?
mix3d
Danke, mix3d. Ich habe Klarstellung hinzugefügt.
MarkN
Danke, dass du das erklärt hast! Diese Lösung funktioniert für mich und ähnelt einigen anderen hier geposteten, obwohl ich nicht verstanden habe, was passiert ist :)
Tim Molloy
3
let data = [
  {
    'name': 'Amir',
    'surname': 'Rahnama'
  }, 
  {
    'name': 'Amir',
    'surname': 'Stevens'
  }
];
let non_duplicated_data = _.uniqBy(data, 'name');
qzttt
quelle
9
Bitte fügen Sie eine Erklärung zu Ihrem Code hinzu, damit zukünftige Besucher verstehen können, was Sie tun. Vielen Dank.
Bugs
Ihre Antwort ist abhängig von einer externen Codebibliothek ...
Taylor A. Leach
3

Ich glaube eine Kombination von reducemit JSON.stringify, um Objekte perfekt und selektiv zu vergleichen das Hinzufügen diejenigen , die nicht bereits im Speicher sind , ist eine elegante Art und Weise.

Beachten Sie, dass dies JSON.stringifyin extremen Fällen, in denen das Array viele Objekte enthält und diese komplex sind, zu einem Leistungsproblem werden kann, ABER für die meiste Zeit ist dies meiner Meinung nach der kürzeste Weg.

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)

Eine andere Art, dasselbe zu schreiben (aber weniger effizient):

collection.reduce((filtered, item) => 
  filtered.some(filteredItem => 
    JSON.stringify(filteredItem ) == JSON.stringify(item)) 
      ? filtered
      : [...filtered, item]
, [])
vsync
quelle
derjenige, der für mich funktioniert! Vielen Dank!
javascript110899
2

Weitere Erkundung der ES6-Möglichkeiten zum Entfernen von Duplikaten aus einem Array von Objekten: Das Setzen des thisArgArguments von Array.prototype.filterto new Setbietet eine anständige Alternative:

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

Es funktioniert jedoch nicht mit Pfeilfunktionen () =>, da dies thisan deren lexikalischen Umfang gebunden ist.

Leonid Pyrlia
quelle
2

es6 Magie in einer Zeile ... lesbar dabei!

// 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]);
Josiah Coad
quelle
2

Einfache Lösung mit ES6-Hilfsmethoden zum Reduzieren und Suchen von Arrays

Funktioniert effizient und einwandfrei!

"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));
KJ Sudarshan
quelle
Das hat mir sehr geholfen, danke
jpisty
1

Wenn es Ihnen nichts ausmacht, dass Ihr eindeutiges Array anschließend sortiert wird, ist dies eine effiziente Lösung:

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

Auf diese Weise müssen Sie nur das aktuelle Element mit dem vorherigen Element im Array vergleichen. Das einmalige Sortieren vor dem Filtern ( O(n*log(n))) ist billiger als das Suchen nach einem Duplikat im gesamten Array für jedes Array-Element ( O(n²)).

Clemens Helm
quelle
1

Dies ist eine einfache Methode, um Doppelspurigkeiten aus einem Array von Objekten zu entfernen.

Ich arbeite viel mit Daten und das ist nützlich für mich.

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

wird in die Konsole drucken:

[[object Object] {
name: "AAA"
}, [object Object] {
name: "BBB"
}]
Juraj
quelle
Diese Lösung wurde entwickelt, um Doppelspurigkeiten aus statischen Arrays zu entfernen. Wenn Sie jedoch Daten aus dem Backend in Datenarrays verschieben, sollten Sie die Verwendung von Ersetzen in Betracht ziehen. In diesem Fall wird der neue Wert, der an das Datenarray gesendet wird, entfernt und der "alte" Wert wird weiterhin im Datenarray gespeichert.
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 ist ein Array von Objekten. Es gibt Objekte mit demselben Wert (hier ein kleines Beispiel, es gibt zwei Objekte mit derselben item_id wie 2). check (id) ist eine Funktion, die prüft, ob ein Objekt mit derselben item_id vorhanden ist oder nicht. Wenn es existiert, geben Sie false zurück, andernfalls true. Schieben Sie das Objekt entsprechend diesem Ergebnis in ein neues Array obj. Die Ausgabe des obigen Codes lautet [{"item_id":1},{"item_id":2}]

Bibin Jaimon
quelle
Fügen Sie eine Beschreibung hinzu
Mathews Sunny
@Billa Ist es in Ordnung?
Bibin Jaimon
1

Haben Sie von der Lodash-Bibliothek gehört? Ich empfehle Ihnen dieses Dienstprogramm, wenn Sie Ihre Logik nicht wirklich auf den Code anwenden möchten und bereits vorhandenen Code verwenden möchten, der optimiert und zuverlässig ist.

Erwägen Sie, ein Array wie dieses zu erstellen

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

Beachten Sie, dass Sie, wenn Sie ein Attribut eindeutig halten möchten, dies möglicherweise mithilfe der lodash-Bibliothek tun können. Hier können Sie _.uniqBy verwenden

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

Diese Methode ist wie _.uniq (die eine Version eines Arrays zurückgibt, in der nur das erste Vorkommen jedes Elements beibehalten wird), außer dass sie Iteratee akzeptiert, die für jedes Element im Array aufgerufen werden, um das Kriterium zu generieren, nach dem Die Eindeutigkeit wird berechnet.

Wenn Sie beispielsweise ein Array mit dem eindeutigen Attribut "Ort" zurückgeben möchten

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

Ebenso, wenn Sie ein eindeutiges Attribut als "Name" möchten

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

Hoffe das hilft.

Prost!

Mayank Gangwal
quelle