Supprimer les doublons d'un tableau d'objets en JavaScript

374

J'ai un objet qui contient un tableau d'objets.

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

Je me demande quelle est la meilleure méthode pour supprimer les objets en double d'un tableau. Ainsi, par exemple, les choses deviendraient ...

{place:"here",name:"stuff"},
{place:"there",name:"morestuff"}
Travis
la source
Voulez-vous dire comment arrêter une table de hachage / un objet avec tous les mêmes paramètres ajoutés à un tableau?
Matthew Lock
1
Mathew -> S'il est plus simple d'empêcher un objet en double d'être ajouté au tableau en premier lieu, au lieu de le filtrer plus tard, oui, ce serait bien aussi.
Travis
2
Cela continue de me surprendre comment les gens nomment leurs variables. Parfois, je pense qu'ils veulent vraiment compliquer inutilement les choses. Suivant pour voir la volonté aaaaa.aaaa.push(...):)
dazito

Réponses:

154

Une méthode primitive serait:

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
la source
15
Vous ne devez jamais utiliser la longueur dans la boucle for, car cela ralentira tout le calcul à chaque itération. Assignez-le à une variable en dehors de la boucle et passez la variable à la place de things.thing.length.
0v3rth3d4wn
12
@aefxx Je ne comprends pas très bien cette fonction, comment gérez-vous la situation où le "lieu" est le même mais le nom est différent, faut-il envisager dup ou non?
Kuan
2
Bien que cela fonctionne, il ne prend pas en charge un tableau trié car la récupération des clés n'est jamais garantie. Donc, vous finissez par le trier à nouveau. Supposons maintenant que le tableau n'ait pas été trié mais que son ordre soit important, il n'y a aucun moyen de vous assurer que l'ordre reste intact
Deepak GM
1
@DeepakGM Vous avez absolument raison. La réponse ne préservera pas (nécessairement) un ordre donné. Si c'est une exigence, il faut chercher une autre solution.
aefxx
Comment pourrais-je modifier ce qui précède pour supprimer des objets d'un tableau qui contiennent X ainsi que dupé?
Ryan Holton
435

Et la es6magie?

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

URL de référence

Une solution plus générique serait:

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

Exemple de Stackblitz

Eydrian
la source
81
Cela peut être raccourci à:things.thing = things.thing.filter((thing, index, self) => self.findIndex(t => t.place === thing.place && t.name === thing.name) === index)
Josh Cole
Marche parfaitement! var uniqueArrayOfObjects = arrayOfObjects.filter (fonction (obj, index, self) {return index === self.findIndex (function (t) {return t ['obj-property'] === obj ['obj-property']) });}); Assurez-vous d'utiliser la syntaxe JS appropriée.
Mohamed Salem Lamiri
Ce sont la syntaxe JS appropriée. La vôtre n'utilise pas 1) les fonctions de flèche grasse 2) le retour implicite ou 3) la notation par points. La vôtre est la syntaxe ES5. Les autres sont principalement ES6 (ECMA2015). Tous sont valables en 2017. Voir le commentaire de jaredwilli.
agm1984
8
@vsync il suffit de prendre la réponse de @ BKM et de la mettre ensemble, une solution générique serait: const uniqueArray = arrayOfObjects.filter((object,index) => index === arrayOfObjects.findIndex(obj => JSON.stringify(obj) === JSON.stringify(object))); jsfiddle.net/x9ku0p7L/28
Eydrian
9
La clé ici est que la méthode findIndex () retourne l'index du premier élément, donc s'il y a un deuxième élément qui correspond, il ne sera jamais trouvé et ajouté pendant le filtre. Je le regardais pendant une minute :)
JBaczuk
111

Si vous pouvez utiliser des bibliothèques Javascript telles que le soulignement ou le lodash, je vous recommande de jeter un œil à la _.uniqfonction dans leurs bibliothèques. De lodash:

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

Fondamentalement, vous passez dans le tableau qui est ici un littéral objet et vous passez l'attribut avec lequel vous souhaitez supprimer les doublons dans le tableau de données d'origine, comme ceci:

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

MISE À JOUR : Lodash a maintenant introduit un .uniqByégalement.

ambodi
la source
3
@Praveen Pds: Ai-je dit quelque chose sur le trait de soulignement dans l'exemple de code? J'ai dit que «lodash» avait cette fonction et le soulignement en avait des similaires. Avant de voter, veuillez lire attentivement les réponses.
ambodi
// Répertorie les objets uniques à l'aide de _underscore.js holdingObject = _.uniq (holdingObject, function (item, key, name) {return item.name;});
praveenpds
26
Remarque: vous devez maintenant utiliser à la uniqByplace de uniq, par exemple _.uniqBy(data, 'name')... documentation: lodash.com/docs#uniqBy
drmrbrewer
83

J'avais exactement la même exigence, pour supprimer les objets en double dans un tableau, basé sur des doublons sur un seul champ. J'ai trouvé le code ici: Javascript: Supprimer les doublons du tableau d'objets

Donc, dans mon exemple, je supprime tout objet du tableau qui a une valeur de chaîne licenseNum en double.

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

Les resultats:

uniqueArray est:

[{"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
la source
1
Cela serait plus utile si la fonction pouvait également filtrer les objets «falsifiés». for(var i in array) { if(array[i][prop]){ //valid lookupObject[array[i][prop]] = array[i]; } else { console.log('falsy object'); } }
Abdul Sadik Yalcin
Pourquoi ne pas réduire la complexité 0 (n) en utilisant: for (let i in originalArray) { if (lookupObject[originalArray[i]['id']] === undefined) { newArray.push(originalArray[i]); } lookupObject[originalArray[i]['id']] = originalArray[i]; }
Tudor B.
c'est le meilleur moyen car il est important de savoir ce que vous voulez ne pas dupliquer. Maintenant, cela peut-il être fait via un réducteur pour les normes e6?
Christian Matthew
70

Doublures les plus courtes pour ES6 +

Trouvez des pièces uniques iddans un tableau.

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

Unique par plusieurs propriétés ( placeet name)

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

Unique par toutes les propriétés (ce sera lent pour les grands tableaux)

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

Gardez la dernière occurrence.

arr.slice().reverse().filter((v,i,a)=>a.findIndex(t=>(t.id === v.id))===i).reverse()
poulets
la source
2
Magie, c'est la vraie réponse
Luis Contreras
48

Un liner avec 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)

Explication:

  1. new Set(myData.map(JSON.stringify))crée un objet Set à l'aide des éléments myData stringifiés.
  2. Définir l'objet garantira que chaque élément est unique.
  3. Ensuite, je crée un tableau basé sur les éléments de l'ensemble créé en utilisant Array.from.
  4. Enfin, j'utilise JSON.parse pour reconvertir l'élément stringifié en objet.
Mμ.
la source
18
le problème étant {a: 1, b: 2} ne sera pas égal à {b: 2, a: 1}
PirateApp
2
gardez à l'esprit qu'il y aurait un problème avec les propriétés Date
MarkosyanArtur
Cette ligne crée des valeurs nulles aléatoires avec un objet ligne qui n'existe pas dans le tableau d'objets d'origine. Peux-tu aider s'il te plait?
B1K
47

En utilisant ES6 + sur une seule ligne, vous pouvez obtenir une liste unique d'objets par clé:

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

Il peut être mis dans une fonction:

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

Voici un exemple de travail:

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

Comment ça marche

Tout d'abord, le tableau est remappé de manière à pouvoir être utilisé comme entrée pour une carte.

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

ce qui signifie que chaque élément du tableau sera transformé en un autre tableau avec 2 éléments; la touche sélectionnée en tant que premier élément et l'ensemble de l' article initial en tant que deuxième élément, ce qu'on appelle une entrée (ex. entrées de tableau , les entrées de la carte ). Et voici le document officiel avec un exemple montrant comment ajouter des entrées de tableau dans le constructeur Map.

Exemple lorsque la clé est en place :

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

Deuxièmement, nous passons ce tableau modifié au constructeur Map et voici la magie qui se produit. La carte éliminera les valeurs des clés en double, en ne conservant que la dernière valeur insérée de la même clé. Remarque : la carte conserve l'ordre d'insertion. ( vérifier la différence entre la carte et l'objet )

nouvelle carte (tableau d'entrée juste mappé ci-dessus)

Troisièmement, nous utilisons les valeurs de la carte pour récupérer les éléments d'origine, mais cette fois sans doublons.

nouvelle carte (mappedArr) .values ​​()

Et la dernière consiste à ajouter ces valeurs dans un nouveau tableau afin qu'il puisse ressembler à la structure initiale et retourner cela:

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

V. Sambor
la source
Cela ne répond pas à la question d'origine car il s'agit d'une recherche de id. La question nécessite que l'objet entier soit unique dans tous les domaines tels que placeetname
L. Holanda
Votre fonction ES6 semble très concise et pratique. Pouvez-vous l'expliquer un peu plus? Que se passe-t-il exactement? Les premier ou dernier doublons sont-ils supprimés? Ou est-ce aléatoire, quel doublon est supprimé? Ce serait utile, merci.
David Schumann
Autant que je sache, une carte avec la valeur de propriété comme clé est créée. Mais ce n'est pas à 100% comment ou si l'ordre du tableau est préservé.
David Schumann
1
Bonjour @DavidSchumann, je mettrai à jour la réponse et expliquerai comment cela fonctionne. Mais pour une réponse courte, l'ordre est préservé et le premier est supprimé ... Pensez simplement à la façon dont il est inséré dans la carte ... il vérifie si la clé existe déjà, elle la mettra à jour, par conséquent la dernière restera
V Sambor
30

Voici une autre option pour le faire en utilisant des méthodes d'itération de tableau si vous avez besoin d'une comparaison uniquement par un champ d'un objet:

    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
la source
Bien que cela ait un ordre supérieur à O (n²), cela correspond à mon cas d'utilisation car la taille de mon tableau sera toujours inférieure à 30. Merci!
Sterex
24

un paquebot est ici

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
la source
1
Agréable et propre si vous ne souhaitez supprimer que des objets avec une seule valeur en double, pas si propre pour les objets entièrement dupliqués.
David Barker
22

Si vous pouvez attendre pour éliminer les doublons après tous les ajouts, l'approche typique consiste d'abord à trier le tableau, puis à éliminer les doublons. Le tri évite l'approche N * N consistant à analyser le tableau pour chaque élément lorsque vous les parcourez.

La fonction "éliminer les doublons" est généralement appelée unique ou uniq . Certaines implémentations existantes peuvent combiner les deux étapes, par exemple, l'uniq du prototype

Ce post a quelques idées à essayer (et certaines à éviter :-)) si votre bibliothèque n'en a pas déjà ! Personnellement, je trouve celui-ci le plus simple:

    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
la source
Cela ne fonctionnera pas pour les objets génériques sans ordre de tri naturel.
Tim Down
Certes, j'ai ajouté une version de comparaison fournie par l'utilisateur.
maccullt
Votre version de comparaison fournie par l'utilisateur ne fonctionnera pas car si votre fonction de comparaison est function(_a,_b){return _a.a===_b.a && _a.b===_b.b;}alors le tableau ne sera pas trié.
graham.reeds
1
Il s'agit d'une fonction de comparaison non valide. From developer.mozilla.org/en/Core_JavaScript_1.5_Reference/… ... fonction compare (a, b) {if (a est inférieur à b selon un critère de classement) return -1; si (a est supérieur à b par le critère de classement) retourne 1; // a doit être égal à b return 0; } ...
maccullt
22

La manière la plus simple est d'utiliser 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і
la source
6
Il est recommandé sur Stack Overflow d'ajouter une explication sur les raisons pour lesquelles votre solution devrait fonctionner, en particulier sur la façon dont la vôtre est meilleure que les autres réponses. Pour plus d'informations, consultez Comment répondre .
Samuel Liew
Cela ne répond pas à la question d'origine car il s'agit d'une recherche de id. La question nécessite que l'objet entier soit unique dans tous les domaines tels que placeetname
L. Holanda
17

C'est une façon générique de le faire: vous passez une fonction qui teste si deux éléments d'un tableau sont considérés comme égaux. Dans ce cas, il compare les valeurs des propriétés nameet placedes deux objets à comparer.

Réponse 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);

Réponse originale 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);
Tim Down
la source
1
Deux objets ne seront pas évalués égaux, même s'ils partagent les mêmes propriétés et valeurs.
kennebec
Oui je sais. Mais bon point, je n'ai pas lu correctement la question: je n'avais pas remarqué que c'était des objets aux propriétés identiques dont il avait besoin pour éliminer. Je vais modifier ma réponse.
Tim Down
1
au lieu de tandis que dans arrayContains- utilisez la méthode Array.prototype..some Renvoie true si l'un des membres du tableau correspond à la condition
MarkosyanArtur
13

Pour en ajouter un de plus à la liste. Utilisation d'ES6 et Array.reduceavec Array.find.
Dans cet exemple, filtrer les objets en fonction d'une guidpropriété.

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

Extension de celui-ci pour permettre la sélection d'une propriété et la compresser en une seule doublure:

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

Pour l'utiliser, passez un tableau d'objets et le nom de la clé que vous souhaitez déduper comme valeur de chaîne:

const result = uniqify(myArrayOfObjects, 'guid')
Pete B
la source
11

Vous pouvez également utiliser Map:

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

Échantillon complet:

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

Résultat:

[
    {
        "place": "here",
        "name": "stuff"
    },
    {
        "place": "there",
        "name": "morestuff"
    }
]
Pragmateek
la source
+1, agréable mais expliquant un peu plus le fonctionnement interne de dedupThings serait bien - du bon côté, je comprends maintenant réduire: D
MimiEAM
11

Dang, les enfants, écrasons cette chose, pourquoi pas nous?

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
la source
Cela ne répond pas à la question d'origine car il s'agit d'une recherche de id. La question nécessite que l'objet entier soit unique dans tous les domaines tels que placeetname
L. Holanda
Il s'agit d'un raffinement d'une généralisation ci-dessus du problème. La question originale a été postée il y a 9 ans, donc l'affiche originale n'est probablement pas inquiète placeet nameaujourd'hui. Quiconque lit ce fil recherche un moyen optimal de dédoubler une liste d'objets, et c'est une façon compacte de le faire.
Cliff Hall
11

Une solution TypeScript

Cela supprimera les objets en double et préservera également les types des objets.

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

la source
2
c'est super et bref!
mojjj
Et super lent aussi ...
L. Holanda
7

Considérant 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
la source
Parfait! Merci ;-)
DonFabiolas
1
Ni l'uniq ni l'uniBBy de lodash n'ont fait l'affaire, mais votre solution l'a fait. Merci! Veuillez cependant indiquer la source de votre code, s'il s'agit d'une copie directe. lodash.com/docs/4.17.10#uniqWith
Manu CJ
5

Une autre option serait de créer une fonction indexOf personnalisée, qui compare les valeurs de la propriété que vous avez choisie pour chaque objet et envelopper cela dans une fonction de réduction.

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
la source
cela a fonctionné très bien pour moi - je l'ai associé au lodash.isequalpackage npm en tant que comparateur d'objet léger pour effectuer un filtrage de tableau unique ... par exemple, un tableau distinct d'objets. Juste échangé au if (_.isEqual(a[i], b)) {lieu de regarder @ une seule propriété
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)

One-liner utilisant ES6 et new Map().

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

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

Détails:-

  1. En faisant .map()sur la liste de données et en convertissant chaque objet individuel en un [key, value]tableau de paires (longueur = 2), le premier élément (clé) serait lestringified version de l'objet et le second (valeur) serait un objectlui-même.
  2. L'ajout de la liste de tableaux créée ci-dessus new Map()aurait la clé commestringified objet et tout ajout de clé entraînerait la substitution de la clé déjà existante.
  3. L'utilisation .values()donnerait MapIterator avec toutes les valeurs d'une carte (obj dans notre cas)
  4. Enfin, spread ...opérateur pour donner un nouveau tableau avec les valeurs de l'étape ci-dessus.
Savan Akbari
la source
4

Voici une solution pour es6 où vous ne souhaitez conserver que le dernier élément. Cette solution est fonctionnelle et conforme au style 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' }]
Michée
la source
Vous pouvez supprimer le doublon et vous pouvez également supprimer tout le doublon avec ce code. Nice
sg28
4

removeDuplicates () prend un tableau d'objets et retourne un nouveau tableau sans aucun objet en double (basé sur la propriété 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);

Résultat attendu:

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

Tout d'abord, nous définissons la valeur de la variable uniq sur un objet vide.

Ensuite, nous filtrons à travers le tableau d'objets. Le filtre crée un nouveau tableau avec tous les éléments qui réussissent le test implémenté par la fonction fournie.

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

Ci-dessus, nous utilisons la fonctionnalité de court-circuitage de &&. Si le côté gauche du && prend la valeur true, il renvoie la valeur à droite du &&. Si le côté gauche est faux, il renvoie ce qui se trouve sur le côté gauche du &&.

Pour chaque objet (obj), nous vérifions uniq pour une propriété nommée la valeur de obj.id (dans ce cas, à la première itération, il vérifierait la propriété «1».) Nous voulons le contraire de ce qu'il retourne (soit vrai ou faux) c'est pourquoi nous utilisons le! dans! uniq [obj.id]. Si uniq a déjà la propriété id, elle renvoie true qui est évaluée à false (!) En disant à la fonction de filtre de ne PAS ajouter cet obj. Cependant, s'il ne trouve pas la propriété obj.id, il renvoie false qui est ensuite évalué à true (!) Et renvoie tout à droite du &&, ou (uniq [obj.id] = true). Il s'agit d'une valeur véridique, indiquant à la méthode de filtrage d'ajouter cet obj au tableau renvoyé, et elle ajoute également la propriété {1: true} à uniq. Cela garantit qu'aucune autre instance obj avec le même identifiant ne sera ajoutée à nouveau.

MarkN
la source
Peut-être expliquer votre code et comment il répond à la question?
mix3d
Merci, mix3d. J'ai ajouté des éclaircissements.
MarkN
Merci d'avoir expliqué cela! Cette solution fonctionne pour moi et est similaire à quelques autres publiées ici, bien que je ne comprenne pas ce qui se passait :)
Tim Molloy
3
let data = [
  {
    'name': 'Amir',
    'surname': 'Rahnama'
  }, 
  {
    'name': 'Amir',
    'surname': 'Stevens'
  }
];
let non_duplicated_data = _.uniqBy(data, 'name');
qzttt
la source
9
Veuillez ajouter une explication autour de votre code afin que les futurs visiteurs puissent comprendre ce que vous faites. Merci.
Bugs
Votre réponse dépend d'une bibliothèque de code externe ...
Taylor A. Leach
3

Je crois qu'une combinaison de reduceavec JSON.stringifypour comparer parfaitement les objets et ajouter sélectivement ceux qui ne sont pas déjà dans l'accumulateur est une manière élégante.

Gardez à l'esprit que cela JSON.stringifypourrait devenir un problème de performances dans les cas extrêmes où le tableau a de nombreux objets et ils sont complexes, MAIS pour la majorité du temps , c'est le chemin le plus court pour aller à mon humble avis.

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)

Une autre façon d'écrire la même chose (mais moins efficace):

collection.reduce((filtered, item) => 
  filtered.some(filteredItem => 
    JSON.stringify(filteredItem ) == JSON.stringify(item)) 
      ? filtered
      : [...filtered, item]
, [])
vsync
la source
celui qui fonctionne pour moi! Merci!
javascript110899
2

Continuer à explorer les moyens d'ES6 de supprimer les doublons du tableau d'objets: définir l' thisArgargument de Array.prototype.filterà new Setfournit une alternative décente:

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

Cependant, il ne fonctionnera pas avec les fonctions fléchées () =>, car il thisest lié à leur portée lexicale.

Leonid Pyrlia
la source
2

es6 magic in one line ... lisible à ça!

// 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
la source
2

Solution simple avec les méthodes d'assistance de tableau ES6 «réduire» et «trouver»

Fonctionne efficacement et parfaitement bien!

"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
la source
Cela m'a beaucoup aidé, merci
jpisty
1

Si cela ne vous dérange pas que votre tableau unique soit trié par la suite, ce serait une solution efficace:

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

De cette façon, vous n'avez qu'à comparer l'élément actuel avec l'élément précédent dans le tableau. Trier une fois avant filtering ( O(n*log(n))) est moins cher que de rechercher un doublon dans le tableau entier pour chaque élément du tableau ( O(n²)).

Heaume Clemens
la source
1

C'est un moyen simple de supprimer la duplicité d'un tableau d'objets.

Je travaille beaucoup avec des données et cela m'est utile.

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

imprimera dans la console:

[[object Object] {
name: "AAA"
}, [object Object] {
name: "BBB"
}]
Juraj
la source
Cette solution est conçue pour supprimer la duplicité du tableau statique, mais lorsque vous poussez les données du backend dans le tableau de données, envisagez d'utiliser replace. Parce que dans ce cas, la nouvelle valeur transmise au tableau de données sera supprimée et "l'ancienne" valeur sera toujours stockée dans le tableau de données.
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 est un tableau d'objets. Il existe des objets ayant la même valeur (ici un petit exemple, il y a deux objets ayant le même item_id que 2). check (id) est une fonction qui vérifie si un objet ayant le même item_id existe ou non. s'il existe, retournez false sinon retournez true. Selon ce résultat, poussez l'objet dans un nouveau tableau obj La sortie du code ci-dessus est [{"item_id":1},{"item_id":2}]

Bibin Jaimon
la source
Ajouter une description
Mathews Sunny
@Billa Ça va?
Bibin Jaimon
1

Avez-vous entendu parler de la bibliothèque Lodash? Je vous recommande cet utilitaire, lorsque vous ne voulez pas vraiment appliquer votre logique au code, et utiliser du code déjà présent qui est optimisé et fiable.

Pensez à créer un tableau comme celui-ci

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

Notez que si vous souhaitez conserver un attribut unique, vous pouvez très bien le faire en utilisant la bibliothèque lodash. Ici, vous pouvez utiliser _.uniqBy

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

Cette méthode est similaire à _.uniq (qui renvoie une version sans doublon d'un tableau, dans laquelle seule la première occurrence de chaque élément est conservée), sauf qu'elle accepte l'itérate qui est invoquée pour chaque élément du tableau pour générer le critère par lequel l'unicité est calculée.

Ainsi, par exemple, si vous souhaitez renvoyer un tableau ayant un attribut unique de «place»

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

De même, si vous voulez un attribut unique comme «nom»

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

J'espère que cela t'aides.

À votre santé!

Mayank Gangwal
la source