web-dev-qa-db-fra.com

Supprimer des objets en double avec Underscore pour Javascript

J'ai ce genre de tableau:

var foo = [ { "a" : "1" }, { "b" : "2" }, { "a" : "1" } ];

Je voudrais le filtrer pour avoir:

var bar = [ { "a" : "1" }, { "b" : "2" }];

J'ai essayé d'utiliser _.uniq, mais je suppose que, parce que { "a" : "1" } n'est pas égal à lui-même, cela ne fonctionne pas. Existe-t-il un moyen de fournir à uniq de soulignement une fonction d’égalité surchargée?

122
plus-

.uniq/ .unique accepte un rappel

var list = [{a:1,b:5},{a:1,c:5},{a:2},{a:3},{a:4},{a:3},{a:2}];

var uniqueList = _.uniq(list, function(item, key, a) { 
    return item.a;
});

// uniqueList = [Object {a=1, b=5}, Object {a=2}, Object {a=3}, Object {a=4}]

Remarques:

  1. Valeur de retour de rappel utilisée pour la comparaison
  2. Premier objet de comparaison avec une valeur de retour unique utilisée comme unique
  3. underscorejs.org ne montre aucune utilisation de rappel
  4. lodash.com montre l'utilisation

Autre exemple: utiliser le rappel pour extraire les marques de voiture, les couleurs d’une liste

231
Shanimal

Si vous souhaitez supprimer les doublons en fonction d'un identifiant, vous pouvez procéder comme suit:

var res = [
  {id: 1, content: 'heeey'},
  {id: 2, content: 'woah'}, 
  {id: 1, content:'foo'},
  {id: 1, content: 'heeey'},
];
var uniques = _.map(_.groupBy(res,function(doc){
  return doc.id;
}),function(grouped){
  return grouped[0];
});

//uniques
//[{id: 1, content: 'heeey'},{id: 2, content: 'woah'}]
38
Petter

Mise en œuvre de la réponse de Shiplu.

var foo = [ { "a" : "1" }, { "b" : "2" }, { "a" : "1" } ];

var x = _.uniq( _.collect( foo, function( x ){
    return JSON.stringify( x );
}));

console.log( x ); // returns [ { "a" : "1" }, { "b" : "2" } ]
17
Larry Battle

Quand j'ai un identifiant d'attribut, c'est ma manière préférée de souligner:

var x = [{i:2}, {i:2, x:42}, {i:4}, {i:3}];
_.chain(x).indexBy("i").values().value();
// > [{i:2, x:42}, {i:4}, {i:3}]
15
tuxbear

Utiliser underscore unique lib est le suivant, je m’offre une liste unique sur la base de _id, puis je renvoie la valeur String de _id:

var uniqueEntities = _.uniq(entities, function (item, key, a) {
                                    return item._id.toString();
                                });
11
Aqib Mumtaz

Voici une solution simple, qui utilise une comparaison d'objet approfondie pour vérifier les doublons (sans recourir à la conversion en JSON, ce qui est inefficace et fastidieux)

var newArr = _.filter(oldArr, function (element, index) {
    // tests if the element has a duplicate in the rest of the array
    for(index += 1; index < oldArr.length; index += 1) {
        if (_.isEqual(element, oldArr[index])) {
            return false;
        }
    }
    return true;
});

Il filtre tous les éléments s'ils ont un duplicata plus tard dans le tableau - de sorte que le dernier élément dupliqué soit conservé.

Le test de duplication utilise _.isEqual qui effectue une comparaison approfondie optimisée entre les deux objets. Pour plus d’informations, consultez le underscore isEqual documentation .

edit: mis à jour pour utiliser _.filter qui est une approche plus propre

10
Joshua Bambrick

Essayez la fonction itérateur

Par exemple, vous pouvez retourner le premier élément

x = [['a',1],['b',2],['a',1]]

_.uniq(x,false,function(i){  

   return i[0]   //'a','b'

})

=> [['' a ', 1], [' b ', 2]]

7
IvanM

avec underscore, j'ai dû utiliser String () dans la fonction iteratee

function isUniq(item) {
    return String(item.user);
}
var myUniqArray = _.uniq(myArray, isUniq);
3
dam1

voici ma solution (coffeescript):

_.mixin
  deepUniq: (coll) ->
    result = []
    remove_first_el_duplicates = (coll2) ->

      rest = _.rest(coll2)
      first = _.first(coll2)
      result.Push first
      equalsFirst = (el) -> _.isEqual(el,first)

      newColl = _.reject rest, equalsFirst

      unless _.isEmpty newColl
        remove_first_el_duplicates newColl

    remove_first_el_duplicates(coll)
    result

exemple:

_.deepUniq([ {a:1,b:12}, [ 2, 1, 2, 1 ], [ 1, 2, 1, 2 ],[ 2, 1, 2, 1 ], {a:1,b:12} ]) 
//=> [ { a: 1, b: 12 }, [ 2, 1, 2, 1 ], [ 1, 2, 1, 2 ] ]
3
szymanowski
var foo = [ { "a" : "1" }, { "b" : "2" }, { "a" : "1" } ];
var bar = _.map(_.groupBy(foo, function (f) { 
        return JSON.stringify(f); 
    }), function (gr) { 
        return gr[0]; 
    }
);

Permet de décomposer cela. Commençons par regrouper les éléments du tableau en fonction de leur valeur stringifiée

var grouped = _.groupBy(foo, function (f) { 
    return JSON.stringify(f); 
});

grouped ressemble à:

{
    '{ "a" : "1" }' = [ { "a" : "1" } { "a" : "1" } ],
    '{ "b" : "2" }' = [ { "b" : "2" } ]
}

Prenons ensuite le premier élément de chaque groupe

var bar = _.map(grouped, function(gr)
    return gr[0]; 
});

bar ressemble à: [ { "a" : "1" }, { "b" : "2" } ]

Mets le tout ensemble:

var foo = [ { "a" : "1" }, { "b" : "2" }, { "a" : "1" } ];
var bar = _.map(_.groupBy(foo, function (f) { 
        return JSON.stringify(f); 
    }), function (gr) { 
        return gr[0]; 
    }
);
0
Kelly Bigley

Je voulais résoudre cette solution simple de manière simple, avec un peu de frais de calcul ... mais n'est-ce pas une solution triviale avec une définition de variable minimale, n'est-ce pas?

function uniq(ArrayObjects){
  var out = []
  ArrayObjects.map(obj => {
    if(_.every(out, outobj => !_.isEqual(obj, outobj))) out.Push(obj)
  })
  return out
}
0
Junji Shimagaki