web-dev-qa-db-fra.com

trait de soulignement/lodash unique par plusieurs propriétés

J'ai un tableau d'objets avec des doublons et j'essaie d'obtenir une liste unique, où l'unicité est définie par un sous-ensemble des propriétés de l'objet. Par exemple,

{a:"1",b:"1",c:"2"}

Et je veux ignorer c dans la comparaison d'unicité.

Je peux faire quelque chose comme 

_.uniq(myArray,function(element) { return element.a + "_" + element+b});

J'espérais pouvoir faire 

_.uniq(myArray,function(element) { return {a:element.a, b:element.b} });

Mais ça ne marche pas. Est-ce que je peux faire quelque chose de ce genre ou dois-je créer une représentation comparable de l'objet si je compare plusieurs propriétés?

23
Jeff Storey

Malheureusement, il ne semble pas y avoir de solution simple. À moins d’écrire votre propre fonction pour cela, vous devrez renvoyer quelque chose qui peut être comparé directement pour l’égalité (comme dans votre premier exemple).

Une méthode serait de simplement .join() les propriétés dont vous avez besoin:

_.uniqBy(myArray, function(elem) { return [elem.a, elem.b].join(); });

Vous pouvez également utiliser _.pick ou _.omit pour supprimer tout ce dont vous n’avez pas besoin. À partir de là, vous pouvez utiliser _.values avec une .join(), ou même simplement JSON.stringify:

_.uniqBy(myArray, function(elem) {
    return JSON.stringify(_.pick(elem, ['a', 'b']));
});

Gardez à l'esprit que les objets ne sont pas déterministes en ce qui concerne l'ordre des propriétés, vous pouvez donc vous en tenir à l'approche de tableau explicite.

P.S. Remplacez uniqBy par uniq pour Lodash <4

27
voithos

Je pense que l'approche join () est toujours la plus simple. En dépit des préoccupations exprimées dans la solution précédente, je pense que le choix du séparateur approprié est la solution pour éviter les pièges identifiés (avec des ensembles de valeurs différents renvoyant la même valeur jointe). N'oubliez pas que le séparateur ne doit pas nécessairement être un seul caractère. Il peut s'agir de n'importe quelle chaîne qui, selon vous, n'apparaîtra pas naturellement dans les données. Je fais cela tout le temps et j'aime bien utiliser '~! $ ~' Comme séparateur. Il peut également inclure des caractères spéciaux tels que\t\r\n etc.

Si les données contenues sont vraiment aussi imprévisibles, peut-être connaissez-vous la longueur maximale et pourriez-vous simplement ajouter à chaque élément une longueur maximale avant de les associer.

1
IndyWill

Les réponses @voithos et @Danail sont un indice. J'ai résolu ce problème en ajoutant une clé unique sur les objets de mon tableau.

Données de départ

const animalArray = [
  { a: 4, b: 'cat', d: 'generic' },
  { a: 5, b: 'cat', d: 'generic' },
  { a: 4, b: 'dog', d: 'generic' },
  { a: 4, b: 'cat', d: 'generic' },
];

Dans l'exemple ci-dessus, je veux que le tableau soit unique par a et b, mais j'ai deux objets qui ont a: 4 et b: 'cat'. En combinant a + b dans une chaîne, je peux obtenir une clé unique à vérifier. 

{ a: 4, b: 'cat', d: 'generic', id: `${a}-${b}` }. // id is now '4-cat'

Remarque: Vous devez évidemment mapper les données ou le faire lors de la création de l'objet car vous ne pouvez pas référencer les propriétés d'un objet dans le même objet.

Maintenant, la comparaison est simple ...

_.uniqBy(animalArray, 'id');

Le tableau résultant aura une longueur de 3, il aura supprimé le dernier duplicata.

0
Trevor