886 votes

Comment supprimer tous les doublons d'un tableau d'objets ?

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

obj = {};

obj.arr = new Array();

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

Je me demande quelle est la meilleure méthode pour supprimer les objets en double d'un tableau. Par exemple, obj.arr deviendrait...

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

0 votes

Voulez-vous dire comment empêcher qu'une table de hachage/un objet avec tous les mêmes paramètres soit ajouté à un tableau ?

9 votes

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.

18 votes

Je suis toujours surpris de voir comment les gens nomment leurs variables. Parfois, je pense qu'ils veulent vraiment rendre les choses inutilement compliquées. La prochaine étape sera aaaaa.aaaa.push(...) :)

938voto

Eydrian Points 2537

Que diriez-vous d'un peu de es6 la magie ?

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

URL de référence

Une solution plus générique serait :

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

En utilisant la stratégie de propriété ci-dessus au lieu de JSON.stringify :

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

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

Vous pouvez ajouter un wrapper si vous voulez que l'option propNames pour être soit un tableau, soit une valeur :

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

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

permettant à la fois getUniqueItemsByProperties('a') y getUniqueItemsByProperties(['a']);

Exemple de Stackblitz

Explication

  • Commencez par comprendre les deux méthodes utilisées :
  • Ensuite, prenez votre idée de ce qui rend vos deux objets égaux et gardez-la en tête.
  • Nous pouvons détecter quelque chose comme un doublon, s'il satisfait au critère auquel nous venons de penser, mais sa position n'est pas à la première instance d'un objet ayant le critère.
  • Nous pouvons donc utiliser le critère ci-dessus pour déterminer si quelque chose est un doublon.

499voto

rturkek Points 77

One liners avec filtre ( Préserve la commande )

Trouver une solution unique id dans un tableau.

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

Si l'ordre n'est pas important, les solutions cartographiques seront plus rapides : Solution avec carte


Unique par de multiples propriétés ( place y name )

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

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

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

Conserver la dernière occurrence en remplaçant findIndex avec findLastIndex .

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

303voto

V. Sambor Points 1559

Utilisation de ES6 en une seule ligne, vous pouvez obtenir une liste unique d'objets par clé :

const unique = [...new Map(arr.map((item, key) => [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 concret :

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 cela fonctionne-t-il ?

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

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

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

Exemple lorsque la touche est place :

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

Ensuite, nous passons ce tableau modifié au constructeur de Map et voilà la magie qui opère. Map va éliminer les valeurs des clés en double, en ne gardant que la dernière valeur insérée de la même clé. Note : La carte conserve l'ordre d'insertion. ( vérifier la différence entre carte et objet )

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

Troisièmement, nous utilisons les valeurs de la carte pour retrouver les éléments originaux, mais cette fois sans les doublons.

nouvelle Map(mappedArr).values()

Et le dernier est d'ajouter ces valeurs dans un nouveau tableau pour qu'il puisse ressembler à la structure initiale et le retourner :

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

244voto

MiXT4PE Points 400

Voici un la voie ES6 courte avec un meilleur runtime que les plus de 70 réponses qui existent déjà :

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

Exemple :

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

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

console.log(filtered)

Comment cela fonctionne :

Array.filter() supprime tous les objets dupliqués en vérifiant si le tableau d'identifiants précédemment mappé inclut l'identifiant actuel ( {id} détruit l'objet en ne conservant que son id). Pour ne filtrer que les doublons réels, il utilise la méthode suivante Array.includes() Le deuxième paramètre de l'article fromIndex avec index + 1 qui ignorera l'objet actuel et tous les objets précédents.

Puisque chaque itération de la filter ne recherchera que le tableau commençant à l'indice courant + 1, ce qui réduit considérablement le temps d'exécution car seuls les objets qui n'ont pas été filtrés précédemment sont vérifiés.

Cela fonctionne évidemment aussi pour toute autre clé qui n'est pas appelée id , plusieurs ou même toutes les touches.

201voto

aefxx Points 10941

Une méthode primitive serait :

const obj = {};

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

things.thing = new Array();

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

78 votes

Vous ne devriez jamais utiliser la longueur dans la boucle for, car cela ralentira tout en la calculant à chaque itération. Attribuez-la à une variable en dehors de la boucle et passez la variable au lieu de things.thing.length.

16 votes

@aefxx Je ne comprends pas bien cette fonction, comment gérez-vous la situation où le "lieu" est le même mais le nom est différent, cela doit-il être considéré comme un dup ou non ?

2 votes

Bien que cela fonctionne, cela ne prend pas en compte un tableau trié puisque la récupération des clés n'est jamais garantie. Donc, vous finissez par le trier à nouveau. Maintenant, supposons que le tableau n'est pas trié mais que son ordre est important, il n'y a aucun moyen de s'assurer que cet ordre reste intact.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X