web-dev-qa-db-fra.com

Comment utiliser l'intersection du trait de soulignement sur des objets?

_.intersection([], [])

ne fonctionne qu'avec des types primitifs, non?

Cela ne fonctionne pas avec des objets. Comment puis-je le faire fonctionner avec des objets (peut-être en cochant le champ "Id")?

var a = [ {'id': 1, 'name': 'jake' }, {'id':4, 'name': 'jenny'} ]
var b = [ {'id': 1, 'name': 'jake' }, {'id': 9, 'name': 'nick'} ]

Dans cet exemple, le résultat devrait être: 

_.intersection(a, b);

[{'id': 1, 'name': 'jake'}];

40
user847495

Vous pouvez créer une autre fonction basée sur la fonction de soulignement. Il vous suffit de modifier une ligne de code de la fonction d'origine:

_.intersectionObjects = function(array) {
    var slice = Array.prototype.slice; // added this line as a utility
    var rest = slice.call(arguments, 1);
    return _.filter(_.uniq(array), function(item) {
      return _.every(rest, function(other) {
        //return _.indexOf(other, item) >= 0;
        return _.any(other, function(element) { return _.isEqual(element, item); });
      });
    });
  };

Dans ce cas, vous utiliseriez maintenant la méthode isEqual () du trait de soulignement au lieu du comparateur d'égalité de JavaScript. Je l'ai essayé avec votre exemple et cela a fonctionné. Voici un extrait de la documentation de underscore concernant la fonction isEqual:

_.isEqual(object, other) 
Performs an optimized deep comparison between the two objects, to determine if they should be considered equal.

Vous pouvez trouver la documentation ici: http://documentcloud.github.com/underscore/#isEqual

J'ai mis le code sur jsFiddle pour que vous puissiez le tester et le confirmer: http://jsfiddle.net/luisperezphd/jrJxT/

24
Luis Perez

Voici un algorithme alternatif qui devrait être flexible et performant. L'une de ces améliorations est que vous pouvez spécifier votre propre fonction de comparaison afin que dans votre cas, vous puissiez simplement comparer l'id s'il s'agit d'un identifiant unique.

function intersectionObjects2(a, b, areEqualFunction) {
    var results = [];

    for(var i = 0; i < a.length; i++) {
        var aElement = a[i];
        var existsInB = _.any(b, function(bElement) { return areEqualFunction(bElement, aElement); });

        if(existsInB) {
            results.Push(aElement);
        }
    }

    return results;
}

function intersectionObjects() {
    var results = arguments[0];
    var lastArgument = arguments[arguments.length - 1];
    var arrayCount = arguments.length;
    var areEqualFunction = _.isEqual;

    if(typeof lastArgument === "function") {
        areEqualFunction = lastArgument;
        arrayCount--;
    }

    for(var i = 1; i < arrayCount ; i++) {
        var array = arguments[i];
        results = intersectionObjects2(results, array, areEqualFunction);
        if(results.length === 0) break;
    }

    return results;
}

Vous pouvez l'utiliser comme ceci:

var a = [ { id: 1, name: 'jake' }, { id: 4, name: 'jenny'} ];
var b = [ { id: 1, name: 'jake' }, { id: 9, name: 'nick'} ];
var c = [ { id: 1, name: 'jake' }, { id: 4, name: 'jenny'}, { id: 9, name: 'nick'} ];

var result = intersectionObjects(a, b, c, function(item1, item2) {
    return item1.id === item2.id;
});

Ou vous pouvez laisser la fonction de côté et elle utilisera la fonction de soulignement _.isEqual (), comme suit:

var result = intersectionObjects(a, b, c);

Vous pouvez le trouver sur jsFiddle ici: http://jsfiddle.net/luisperezphd/43vksdn6/

23
Luis Perez

Les méthodes de tableau en soulignement sont très puissantes, vous n’auriez besoin que de quelques lignes pour accomplir ce que vous voulez faire:

var a = [ {'id': 1, 'name': 'jake' }, {'id':4, 'name': 'jenny'} ];
var b = [ {'id': 1, 'name': 'jake' }, {'id': 9, 'name': 'nick'} ];

var result = _(a).chain().map(function(ea) {
    return _.find(b, function(eb) {return ea.id == eb.id;});
}).compact().value();

Si vous avez de grands tableaux, vous pouvez vous débarrasser de l'appel compact() avec une ligne supplémentaire:

var result = [];
_.each(a, function(ea) {
    var entry = _.find(b, function(eb) {return ea.id == eb.id;});
    if (entry) result.Push(entry);
});
5
Julian D.

Je voudrais partager ma général solution pour ces cas.

J'ai ajouté une fonction générale à souligner, en utilisant mixin, qui effectue une opération "array" binaire sur deux collections, selon une fonction de hachage donnée:

_.mixin({
    collectionOperation: function(arr1, arr2, hash, action) {
        var iArr1 = _(arr1).indexBy(hash)
            , iArr2 = _(arr2).indexBy(hash);
        return action(_(iArr1).keys(), _(iArr2).keys()).map(function (id) {
            return iArr1[id] || iArr2[id];
        });
    }
});

Exemple d'utilisation:

_([{id:1,v:'q'},{id:2,v:'p'}]).collectionOperation([{id:3,v:'pq'}], 'id', _.union )

Notez que 'id' peut être remplacé par une fonction.

Je crois que cette solution est O (n + m).

4
Jacob

Dans Lodash 4.0.0. On peut essayer comme ça

var a = [ {'id': 1, 'name': 'jake' }, {'id':4, 'name': 'jenny'} ];
var b = [ {'id': 1, 'name': 'jake' }, {'id': 9, 'name': 'nick'} ];

_.intersectionBy(a, b, 'id');

Sortie:

[{'id': 1, 'name': 'jake'}];

3
Raja Jaganathan

Techniquement, cela fonctionne sur les objets, mais vous devez faire attention à l'égalité des références.

var jake = {'id': 1, 'name': 'jake' },
    jenny = {'id':4, 'name': 'jenny'},
    nick =  {'id': 9, 'name': 'nick'};
var a = [jake, jenny]
var b = [jake, nick];

_.intersection(a, b);
// is
[jake]
3
Joe
var a = [ {'id': 1, 'name': 'jake' }, {'id':4, 'name': 'jenny'} ];
var b = [ {'id': 1, 'name': 'jake' }, {'id': 9, 'name': 'nick'} ];

Fonction de travail:

 function intersection(a,b){
  var c=[];
   for(m in a){
      for(n in b){
         if((a[m].id==a[n].id)&&(a[m].name==b[n].name))
                 c.Push(a[m]);          
      }}
    return c;
  }
console.log(intersection(a,b));

J'ai également essayé le code dans jQuery spécialement après la suggestion de Pointy. La comparaison doit être personnalisable selon la structure de l'objet JSON.

<script type="text/javascript">
jQuery(document).ready(function(){
    var a = [ {'id': 1, 'name': 'jake' }, {'id':4, 'name': 'jenny'} ];
    var b = [ {'id': 1, 'name': 'jake' }, {'id': 9, 'name': 'nick'} ];
    var c=[];
    jQuery.each(a, function(ka,va) {
       jQuery.each(b, function(kb,vb) {      
                if(compare(va,vb))
                    c.Push(va); 
     });   
    });
     console.log(c);  
});
function compare(a,b){
  if(a.id==b.id&&a.name==b.name)
     return true;
  else return false;
}
</script>
2
Umesh Patil

Si vous voulez comparer uniquement des objets:

b = {"1":{"prod":"fibaro"},"2":{"prod":"aeotec"},"3":{"prod":"sw"}}; 
a = {"1":{"prod":"fibaro"}};


_.intersectObjects = function(a,b){
    var m = Object.keys(a).length;
    var n = Object.keys(b).length;
    var output;
    if (m > n) output = _.clone(a); else output = _.clone(b);

    var keys = _.xor(_.keys(a),_.keys(b));
    for(k in keys){
        console.log(k);
        delete output[keys[k]];
    }
    return output;
}
_.intersectObjects(a,b); // this returns { '1': { prod: 'fibaro' } }
0
giuseppe