Rimuovi i duplicati da una matrice di oggetti in JavaScript


374

Ho un oggetto che contiene una matrice di oggetti.

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

Mi chiedo quale sia il metodo migliore per rimuovere oggetti duplicati da un array. Quindi, per esempio, things.thing diventerebbe ...

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

Vuoi dire come fermare un hashtable / object con tutti gli stessi parametri aggiunti ad un array?
Matthew Lock,

1
Mathew -> Se in primo luogo è più semplice impedire che un oggetto duplicato venga aggiunto all'array, invece di filtrarlo in un secondo momento, sì, anche questo andrebbe bene.
Travis

2
Continua a sorprendermi come le persone chiamano le loro variabili. A volte penso che vogliano davvero renderlo inutilmente complicato. Avanti per vedere sarà aaaaa.aaaa.push(...):)
dazito

Risposte:


154

Un metodo primitivo sarebbe:

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
Non dovresti mai usare la lunghezza nel ciclo for, perché rallenterà tutto calcolandolo su ogni iterazione. Assegnalo a una variabile esterna al ciclo e passa la variabile invece di things.thing.length.
0v3rth3d4wn,

12
@aefxx Non capisco bene questa funzione, come gestisci la situazione in cui il "posto" è lo stesso ma il nome è diverso, dovrebbe essere considerato dup o no?
Kuan,

2
Sebbene funzioni, non si occupa di un array ordinato poiché il recupero delle chiavi non è mai garantito dall'ordine. Quindi, finisci per riordinarlo di nuovo. Supponiamo ora che l'array non sia stato ordinato ma che il suo ordine sia importante, non c'è modo di assicurarti che l'ordine rimanga intatto
Deepak GM

1
@DeepakGM Hai perfettamente ragione. La risposta non preserverà (necessariamente) un determinato ordine. Se questo è un requisito, si dovrebbe cercare un'altra soluzione.
aefxx,

Come posso modificare quanto sopra per rimuovere oggetti da un array che contiene X e de-duped?
Ryan Holton

435

Che ne dici di un po 'di es6magia?

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

URL di riferimento

Una soluzione più generica sarebbe:

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

Esempio Stackblitz


81
Questo può essere abbreviato in:things.thing = things.thing.filter((thing, index, self) => self.findIndex(t => t.place === thing.place && t.name === thing.name) === index)
Josh Cole

Funziona perfettamente! var uniqueArrayOfObjects = arrayOfObjects.filter (funzione (obj, index, self) {indice di ritorno === self.findIndex (funzione (t) {return t ['obj-property'] === obj ['obj-property'] });}); Assicurati di utilizzare la sintassi JS corretta.
Mohamed Salem Lamiri,

Quelli sono la sintassi JS corretta. Il tuo non sta usando 1) funzioni freccia grassa 2) ritorno implicito o 3) notazione con punti. La tua è sintassi ES5. Gli altri sono principalmente ES6 (ECMA2015). Tutti sono validi nel 2017. Vedi il commento di jaredwilli.
agm1984,

8
@vsync basta prendere la risposta di @ BKM e metterla insieme, una soluzione generica sarebbe: const uniqueArray = arrayOfObjects.filter((object,index) => index === arrayOfObjects.findIndex(obj => JSON.stringify(obj) === JSON.stringify(object))); jsfiddle.net/x9ku0p7L/28
Eydrian,

9
La chiave qui è che il metodo findIndex () restituisce l'indice del primo elemento, quindi se c'è un secondo elemento che corrisponde, non verrà mai trovato e aggiunto durante il filtro. Lo stavo fissando da un minuto :)
JBaczuk,

111

Se puoi usare librerie Javascript come underscore o lodash, ti consiglio di dare un'occhiata alla _.uniqfunzione nelle loro librerie. Da lodash:

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

Fondamentalmente, si passa alla matrice che qui è un oggetto letterale e si passa l'attributo con cui si desidera rimuovere i duplicati nella matrice di dati originale, in questo modo:

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

AGGIORNAMENTO : Lodash ora ha introdotto anche un .uniqBy.


3
@Praveen Pds: ho detto qualcosa sul trattino basso nell'esempio di codice? Ho detto che 'lodash' ha questa funzione e il carattere di sottolineatura ha funzioni simili. Prima di votare verso il basso, leggi attentamente le risposte.
Ambodi,

// Elenca gli oggetti univoci usando _underscore.js holdingObject = _.uniq (holdingObject, funzione (item, key, name) {return item.name;});
praveenpds,

26
Nota: ora è necessario utilizzare uniqByinvece di uniq, ad esempio _.uniqBy(data, 'name')... documentazione: lodash.com/docs#uniqDa
drmrbrewer

83

Avevo esattamente lo stesso requisito, per rimuovere oggetti duplicati in un array, basato su duplicati su un singolo campo. Ho trovato il codice qui: Javascript: Rimuovi i duplicati dall'array di oggetti

Quindi, nel mio esempio, sto rimuovendo qualsiasi oggetto dall'array che ha un valore duplicato di stringa 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));

I risultati:

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

1
Ciò sarebbe più utile se la funzione potesse filtrare anche gli oggetti "falsi". for(var i in array) { if(array[i][prop]){ //valid lookupObject[array[i][prop]] = array[i]; } else { console.log('falsy object'); } }
Abdul Sadik Yalcin,

Perché non ridurre la complessità 0 (n) usando: for (let i in originalArray) { if (lookupObject[originalArray[i]['id']] === undefined) { newArray.push(originalArray[i]); } lookupObject[originalArray[i]['id']] = originalArray[i]; }
Tudor B.

questo è il modo migliore perché è importante sapere che cosa non si vuole duplicare. Ora è possibile farlo tramite il riduttore per gli standard e6?
Christian Matthew,

70

Liner uno più corto per ES6 +

Trova elementi unici idin un array.

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

Unico per più proprietà ( placee name)

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

Unico per tutte le proprietà (sarà lento per array di grandi dimensioni)

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

Mantieni l'ultima occorrenza.

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

2
Magia, questa è la vera risposta
Luis Contreras,

48

Una fodera usando 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)

Spiegazione:

  1. new Set(myData.map(JSON.stringify))crea un oggetto Set usando gli elementi myData stringiti.
  2. Set object assicurerà che ogni elemento sia unico.
  3. Quindi creo un array basato sugli elementi del set creato usando Array.from.
  4. Infine, uso JSON.parse per riconvertire l'elemento con stringhe in un oggetto.

18
il problema è {a: 1, b: 2} non sarà uguale a {b: 2, a: 1}
PirateApp

2
tieni presente che ci sarebbero problemi con le proprietà Date
MarkosyanArtur

Questa riga crea valori null casuali con un oggetto riga che non esiste nella matrice originale di oggetti. Potete per favore aiutare?
B1K,

47

Utilizzando ES6 + in una sola riga è possibile ottenere un elenco univoco di oggetti per chiave:

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

Può essere messo in una funzione:

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

Ecco un esempio funzionante:

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

Come funziona

Innanzitutto l'array viene rimappato in modo tale da poter essere utilizzato come input per una mappa.

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

ciò significa che ciascun elemento dell'array verrà trasformato in un altro array con 2 elementi; la chiave selezionata come primo elemento e l'intero elemento iniziale come secondo elemento, questo è chiamato una voce (es. voci di array , voci di mappa ). Ed ecco il documento ufficiale con un esempio che mostra come aggiungere voci di array nel costruttore di mappe.

Esempio quando la chiave è posizionata :

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

In secondo luogo, passiamo questo array modificato al costruttore della mappa e qui sta accadendo la magia. Mappa eliminerà i valori delle chiavi duplicate, mantenendo solo l'ultimo valore inserito della stessa chiave. Nota : la mappa mantiene l'ordine di inserimento. ( controlla la differenza tra Mappa e oggetto )

nuova mappa (array di voci appena mappato sopra)

Terzo, utilizziamo i valori della mappa per recuperare gli elementi originali, ma questa volta senza duplicati.

nuova mappa (mappedArr) .values ​​()

E l'ultimo è quello di aggiungere quei valori in un nuovo array nuovo in modo che possa apparire come la struttura iniziale e restituire che:

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


Questo non risponde alla domanda originale in quanto si tratta di cercare un id. La domanda richiede che l'intero oggetto sia unico in tutti i campi come placeename
L. Holanda il

La tua funzione ES6 sembra molto concisa e pratica. Puoi spiegarlo un po 'di più? Cosa sta succedendo esattamente? Vengono rimossi i primi o gli ultimi duplicati? O è casuale, quale duplicato viene rimosso? Sarebbe utile, grazie.
David Schumann,

Per quanto ne so, viene creata una mappa con il valore della proprietà come chiave. Ma non è al 100% come o se l'ordine dell'array viene preservato.
David Schumann il

1
Ciao @DavidSchumann, aggiornerò la risposta e spiegherò come funziona. Ma per una breve risposta l'ordine viene conservato e il primo viene rimosso ... Basti pensare a come viene inserito nella mappa ... controlla se la chiave esiste già lo aggiornerà, quindi l'ultimo rimarrà
V Sambor il

30

Ecco un'altra opzione per farlo usando i metodi di iterazione dell'array se hai bisogno di un confronto solo per un campo di un oggetto:

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

Sebbene questo abbia un ordine maggiore di O (n²), questo si adatta al mio caso d'uso poiché la dimensione della mia matrice sarà sempre inferiore a 30. Grazie!
Sterex,

24

una fodera è qui

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
Bello e pulito se si desidera rimuovere solo oggetti con un singolo valore duplicato, non così pulito per oggetti completamente duplicati.
David Barker,

22

Se puoi aspettare di eliminare i duplicati fino a dopo tutte le aggiunte, l'approccio tipico è innanzitutto ordinare l'array e quindi eliminare i duplicati. L'ordinamento evita l'approccio N * N di scansionare l'array per ciascun elemento mentre li percorri.

La funzione "elimina duplicati" viene in genere definita unica o uniq . Alcune implementazioni esistenti possono combinare le due fasi, ad es. Uniq del prototipo

Questo post ha alcune idee da provare (e alcune da evitare :-)) se la tua libreria non ne ha già una ! Personalmente trovo questo il più semplice:

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

Ciò non funzionerà per oggetti generici senza un ordinamento naturale.
Tim Down

È vero, ho aggiunto una versione di confronto fornita dall'utente.
Maccullt,

La versione di confronto fornita dall'utente non funzionerà perché se la funzione di confronto è function(_a,_b){return _a.a===_b.a && _a.b===_b.b;}attiva, l'array non verrà ordinato.
graham.reeds

1
Questa è una funzione di confronto non valida. Da developer.mozilla.org/it/Core_JavaScript_1.5_Reference/… ... funzione compare (a, b) {if (a è inferiore a b per alcuni criteri di ordinazione) restituisce -1; se (a è maggiore di b per il criterio di ordinazione) restituisce 1; // a deve essere uguale a b return 0; } ...
maccullt

22

Il modo più semplice è usare 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
È buona norma su Stack Overflow aggiungere una spiegazione sul perché la soluzione dovrebbe funzionare, in particolare su come la tua sia migliore delle altre risposte. Per maggiori informazioni leggi Come rispondere .
Samuel Liew

Questo non risponde alla domanda originale in quanto si tratta di cercare un id. La domanda richiede che l'intero oggetto sia unico in tutti i campi come placeename
L. Holanda il

17

Questo è un modo generico per farlo: si passa in una funzione che verifica se due elementi di un array sono considerati uguali. In questo caso, confronta i valori delle proprietà namee placedei due oggetti da confrontare.

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

Risposta ES3 originale

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
Due oggetti non valuteranno uguali, anche se condividono le stesse proprietà e valori.
Kennebec,

Si, lo so. Ma il punto giusto, non sono riuscito a leggere correttamente la domanda: non avevo notato che erano gli oggetti con proprietà identiche che aveva bisogno di eliminare. Modificherò la mia risposta.
Tim Down

1
anziché all'interno di arrayContains- usa il metodo Array.prototype..some Restituisce vero se uno dei membri dell'array soddisfa la condizione
MarkosyanArtur

13

Per aggiungerne un altro all'elenco. Utilizzando ES6 e Array.reducecon Array.find.
In questo esempio, filtrare gli oggetti in base a una guidproprietà.

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

Estendere questo per consentire la selezione di una proprietà e comprimerlo in un unico liner:

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

Per usarlo, passa una matrice di oggetti e il nome della chiave su cui desideri decodificare come valore stringa:

const result = uniqify(myArrayOfObjects, 'guid')

11

Puoi anche usare un Map:

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

Campione completo:

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

Risultato:

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

+1, bello però spiegare un po 'di più il lavoro interiore del dedupCose sarebbero buone - dal lato positivo ora capisco ridurre: D
MimiEAM

11

Dang, ragazzi, buttiamo giù questa cosa, perché no?

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


Questo non risponde alla domanda originale in quanto si tratta di cercare un id. La domanda richiede che l'intero oggetto sia unico in tutti i campi come placeename
L. Holanda il

Questo è un perfezionamento di una generalizzazione del problema di cui sopra. La domanda originale è stata pubblicata 9 anni fa, quindi il poster originale probabilmente non è preoccupato placee nameoggi. Chiunque legga questo thread è alla ricerca di un modo ottimale per deduplicare un elenco di oggetti, e questo è un modo compatto per farlo.
Cliff Hall,

11

Una soluzione TypeScript

Ciò rimuoverà gli oggetti duplicati e preserverà anche i tipi di oggetti.

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

2
questo è fantastico e breve!
Mojjj,

E anche super lento ...
L. Holanda il

7

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

Perfetto ! Grazie ;-)
DonFabiolas

1
Né uniq né uniqBy di lodash hanno fatto il trucco, ma la tua soluzione ha fatto. Grazie! Fornisci comunque la fonte del tuo codice, se è una copia diretta. lodash.com/docs/4.17.10#uniqWith
Manu CJ

5

Un'altra opzione sarebbe quella di creare una funzione indexOf personalizzata, che confronta i valori della proprietà scelta per ciascun oggetto e lo avvolge in una funzione di riduzione.

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

questo ha funzionato alla grande per me - l'ho abbinato al lodash.isequalpacchetto npm come un comparatore di oggetti leggero per eseguire un filtraggio di array univoco ... ad esempio un array distinto di oggetti. Appena scambiato if (_.isEqual(a[i], b)) {invece di cercare @ una singola proprietà
SliverNinja - MSFT il

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)

One-liner con ES6 e new Map().

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

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

Dettagli:-

  1. Facendo .map()sulla lista dei dati e convertendo ogni singolo oggetto in un [key, value]array di coppie (lunghezza = 2), il primo elemento (chiave) sarebbe la stringifiedversione dell'oggetto e il secondo (valore) sarebbe un objectse stesso.
  2. L'aggiunta dell'elenco di array sopra creato new Map()avrebbe la chiave come stringifiedoggetto e qualsiasi aggiunta della stessa chiave comporterebbe l'override della chiave già esistente.
  3. L'utilizzo .values()darebbe a MapIterator tutti i valori in una mappa ( objnel nostro caso)
  4. Infine, l' spread ...operatore fornisce un nuovo array con i valori del passaggio precedente.

4

Ecco una soluzione per es6 in cui desideri conservare solo l'ultimo elemento. Questa soluzione è funzionale e conforme allo stile 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' }]

Puoi rimuovere il duplicato e puoi anche rimuovere tutto il duplicato con questo codice. Nizza
sg28,

4

removeDuplicates () accetta un array di oggetti e restituisce un nuovo array senza oggetti duplicati (basato sulla proprietà 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);

Risultato previsto:

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

Innanzitutto, impostiamo il valore della variabile uniq su un oggetto vuoto.

Successivamente, filtriamo attraverso l'array di oggetti. Filter crea un nuovo array con tutti gli elementi che superano il test implementato dalla funzione fornita.

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

Sopra, utilizziamo la funzionalità di corto circuito di &&. Se il lato sinistro di && restituisce true, restituisce il valore a destra di &&. Se il lato sinistro è falso, restituisce ciò che si trova sul lato sinistro di &&.

Per ogni oggetto (obj) controlliamo uniq per una proprietà chiamata valore di obj.id (In questo caso, nella prima iterazione verificherebbe la proprietà '1'). Vogliamo l'opposto di ciò che restituisce (sia vero o false) che è il motivo per cui usiamo il! in! uniq [obj.id]. Se uniq ha già la proprietà id, restituisce true che restituisce false (!) Dicendo alla funzione filtro NOT di aggiungere quell'oggetto. Tuttavia, se non trova la proprietà obj.id, restituisce false che restituisce true (!) E restituisce tutto a destra di && o (uniq [obj.id] = true). Questo è un valore vero, che dice al metodo di filtro di aggiungere quell'oggetto all'array restituito e aggiunge anche la proprietà {1: true} a uniq. Ciò garantisce che qualsiasi altra istanza obj con lo stesso ID non verrà aggiunta di nuovo.


Forse spiega il tuo codice e come risponde alla domanda?
mix3d

Grazie, mix3d. Ho aggiunto chiarimenti.
MarkN,

Grazie per aver spiegato questo! Questa soluzione funziona per me ed è simile a un paio di altri pubblicati qui, anche se non capivo cosa stesse succedendo :)
Tim Molloy

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

9
Aggiungi una spiegazione intorno al tuo codice in modo che i futuri visitatori possano capire cosa stai facendo. Grazie.
Bug

La tua risposta dipende da una libreria di codici esterna ...
Taylor A. Leach

3

Credo che una combinazione di reducecon JSON.stringifyper confrontare perfettamente gli oggetti e l' aggiunta selettiva di coloro che non sono già nell'accumulatore sia un modo elegante.

Tieni presente che JSON.stringifypotrebbe diventare un problema di prestazioni in casi estremi in cui l'array ha molti oggetti e sono complessi, MA per la maggior parte del tempo , questo è il modo più breve per passare a 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)

Un altro modo di scrivere lo stesso (ma meno efficiente):

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

quello che funziona per me! grazie!
javascript110899

2

Continuando ad esplorare i modi ES6 di rimuovere i duplicati dalla matrice di oggetti: impostare l' thisArgargomento Array.prototype.filterto new Setfornisce un'alternativa decente:

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

Tuttavia, non funzionerà con le funzioni freccia () =>, poiché thisè legato al loro ambito lessicale.


2

magia es6 in una riga ... leggibile a quello!

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

Soluzione semplice con i metodi di supporto dell'array ES6 "ridurre" e "trova"

Funziona in modo efficiente e perfettamente bene!

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

Questo mi ha aiutato molto, grazie
jpisty il

1

Se non ti dispiace che il tuo array unico venga ordinato in seguito, questa sarebbe una soluzione efficiente:

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

In questo modo, devi solo confrontare l'elemento corrente con l'elemento precedente nella matrice. L'ordinamento una volta prima di filtering ( O(n*log(n))) è più economico della ricerca di un duplicato nell'intero array per ogni elemento dell'array ( O(n²)).


1

Questo è un modo semplice per rimuovere la duplicità dall'array di oggetti.

Lavoro molto con i dati e questo è utile per me.

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

stamperà sulla console:

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

Questa soluzione è progettata per rimuovere la duplicità dall'array statico, ma quando si spinge i dati dal back-end nell'array di dati, considerare l'utilizzo di sostituire. Perché in questo caso il nuovo valore inviato all'array di dati verrà rimosso e il "vecchio" valore verrà comunque archiviato nell'array di dati.
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 è una matrice di oggetti. Esistono oggetti con lo stesso valore (qui un piccolo esempio, ci sono due oggetti con lo stesso item_id di 2). check (id) è una funzione che controlla se esiste o meno un oggetto con lo stesso item_id. se esiste restituisce false, altrimenti restituisce true. Secondo tale risultato, spingere l'oggetto in un nuovo array obj L'output del codice sopra è [{"item_id":1},{"item_id":2}]


Aggiungi una descrizione
Mathews Sunny

@Billa Va bene?
Bibin Jaimon,

1

Hai sentito parlare della biblioteca di Lodash? Ti consiglio questa utility, quando non vuoi davvero applicare la tua logica al codice, e utilizzare il codice già presente che è ottimizzato e affidabile.

Prendi in considerazione la creazione di un array come questo

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

Si noti che se si desidera mantenere un attributo univoco, è possibile farlo utilizzando la libreria lodash. Qui puoi usare _.uniqBy

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

Questo metodo è simile a _.uniq (che restituisce una versione senza duplicati di un array, in cui viene conservata solo la prima occorrenza di ciascun elemento) tranne per il fatto che accetta l'iterato che viene invocato per ciascun elemento dell'array per generare il criterio con cui l'unicità è calcolata.

Quindi, ad esempio, se si desidera restituire un array con attributo univoco di "place"

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

Allo stesso modo, se si desidera un attributo univoco come 'nome'

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

Spero che sia di aiuto.

Saluti!

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.