2011-12-29 11 views
38
_.intersection([], []) 

केवल आदिम प्रकारों के साथ काम करता है, है ना?वस्तुओं पर अंडरस्कोर के "चौराहे" का उपयोग कैसे करें?

यह वस्तुओं के साथ काम नहीं करता है। मैं इसे ऑब्जेक्ट्स के साथ कैसे काम कर सकता हूं (शायद "आईडी" फ़ील्ड को देखकर)?

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

इस उदाहरण में, परिणाम होना चाहिए:

_.intersection(a, b); 

[{ 'आईडी': 1, 'नाम': 'जेक'}];

+23

यह आश्चर्यजनक है कि इनमें से कोई भी एपीआई समानता-परीक्षक फ़ंक्शन को पारित करने की अनुमति नहीं देता है। – Pointy

उत्तर

24

आप अंडरस्कोर के फ़ंक्शन के आधार पर एक और फ़ंक्शन बना सकते हैं।

_.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); }); 
     }); 
    }); 
    }; 

इस मामले अब आप अंडरस्कोर के isEqual() विधि के बजाय जावास्क्रिप्ट का समानता comparer का उपयोग किया था में: आप केवल मूल कार्य से कोड की एक पंक्ति बदलना होगा। मैंने आपके उदाहरण के साथ कोशिश की और यह काम किया। तो आप का परीक्षण करने और यह पुष्टि कर सकते हैं http://documentcloud.github.com/underscore/#isEqual

मैं jsFiddle पर कोड डाल: http://jsfiddle.net/luisperezphd/jrJxT/

+4

यह 3 लूप है इसलिए मूल रूप से ओ (एन^3) निश्चित रूप से आप बेहतर कर सकते हैं। (ओ (nlogn) – Raynos

+1

अच्छा बिंदु रेनोस, मैं जितना संभव हो उतना संभव था जितना संभव था, यह केवल अंडरस्कोर के मौजूदा अंतर() फ़ंक्शन का एक छोटा सा था जिसे वह उपयोग करने का उल्लेख करता है और इसलिए प्रदर्शन करने वाला मुझे लगता है कि वह खुश है –

+0

रेनोस, मैंने नीचे एक वैकल्पिक एल्गोरिदम प्रदान किया है कि आप * बेहतर * हो सकते हैं। –

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

कार्य समारोह:

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

मैं भी विशेष रूप से नुकीले के सुझाव के बाद jQuery में कोड की कोशिश की है। तुलना 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> 
+1

सरणी पर 'इन ... इन' का उपयोग करना एक अच्छा विचार नहीं है। – Pointy

+0

@ पॉइंट। तो क्या कर सकते हैं ? यहां, for..in किसी ऑब्जेक्ट में सभी तत्वों को फिर से सक्रिय करें। यहां मूल उद्देश्य सभी उप-वस्तुओं की तुलना किसी दूसरे के साथ करना है। –

+0

ठीक है जब ऐरे उदाहरण पारित हो जाते हैं तो कोड संख्यात्मक सूचकांक पर पुनरावृत्त हो सकता है। "के लिए ..." के साथ समस्या यह है कि यह भ्रमित हो सकता है क्योंकि इसमें गुणों को शामिल किया जाएगा जो ऐरे प्रोटोटाइप ऑब्जेक्ट पर हो सकते हैं। – Pointy

3

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

आप प्रलेखन यहां पा सकते हैं: यहाँ isEqual समारोह के बारे में अंडरस्कोर के दस्तावेज़ से एक अंश है

तकनीकी रूप से, यह वस्तुओं पर काम करता है, लेकिन आपको संदर्भ समानता से सावधान रहना होगा।

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] 
5

अंडरस्कोर में सरणी विधियों बहुत शक्तिशाली हैं, आप केवल कि आप क्या करना चाहते हैं पूरा करने के लिए कुछ लाइनें आवश्यकता चाहिए:

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

आप बड़े सरणियों है, तो आप compact() से छुटकारा पा सकते एक अतिरिक्त लाइन के साथ कॉल करें:

var result = []; 
_.each(a, function(ea) { 
    var entry = _.find(b, function(eb) {return ea.id == eb.id;}); 
    if (entry) result.push(entry); 
}); 
+1

यह समय में वर्गबद्ध है और यह खराब है – user2846569

+0

सच है, यह ओ (एन * एम) है। आपके डेटा सेट के आकार के आधार पर (उदाहरण के लिए कुछ hund लाल वस्तुओं) यह संभवतः एक समस्या नहीं होगी।यदि ऐसा है, तो आपको शायद एक पूरी तरह से अलग दृष्टिकोण की आवश्यकता होगी: क्रमबद्ध Arrays का उपयोग करें, कुछ प्रकार के अनुक्रमण ... –

+0

ज्यादातर मामलों में आप सही हैं, लेकिन आप उस बिंदु को याद कर सकते हैं जहां डेटा बढ़ता है और प्रदर्शन घटता है और दूसरी बात यह है कि आपके पास अधिकांश जगहों पर कोड है, आइए 100 आइटमों के साथ कहें कि यह 100x गुना धीमा है, और बड़े ऐप के लिए यह ध्यान देने योग्य हो सकता है। लेकिन निश्चित रूप से हमेशा प्रत्येक मामले का अध्ययन अलग से किया जाना चाहिए। – user2846569

23

यहां एक वैकल्पिक एल्गोरिदम है जो लचीला होना चाहिए और बेहतर प्रदर्शन करना चाहिए। उनमें से एक सुधार यह है कि आप अपना खुद का तुलना फ़ंक्शन निर्दिष्ट कर सकते हैं ताकि आपके मामले में आप आईडी की तुलना कर सकें यदि यह एक अद्वितीय पहचानकर्ता है।रेखांकित _.isEqual() फ़ंक्शन, इसलिए जैसे

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

या आप समारोह छोड़ सकते हैं और इसका इस्तेमाल होगा:

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

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

आप इस तरह उपयोग कर सकते हैं आप इसे यहां जेएसफ़िल्ड पर पा सकते हैं: http://jsfiddle.net/luisperezphd/43vksdn6/

+0

धन्यवाद, इससे मेरी वर्तमान परियोजना में बहुत मदद मिली। –

+0

महान समाधान, धन्यवाद! – Fabio

+0

बेस्ट उत्तर, क्योंकि यह ceratin तत्व – Lightning3

4

मैं अपना जीन साझा करना चाहता हूं उन मामलों के लिए राल समाधान।

मैं एक सामान्य समारोह को रेखांकित करने के लिए जोड़ा, mixin है, जो दो संग्रह पर एक बाइनरी 'सरणी' कार्रवाई निष्पादित करता है का उपयोग करते हुए, किसी दिए गए हैश समारोह के अनुसार:

_.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]; 
     }); 
    } 
}); 

प्रयोग उदाहरण:

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

ध्यान दें कि 'id' को फ़ंक्शन के साथ प्रतिस्थापित किया जा सकता है।

मुझे विश्वास है कि यह समाधान ओ (एन + एम) है।

+0

को हटाकर इसका शुद्ध जेएस समाधान पोस्ट कर सकता है एक प्रदर्शन परीक्षण अद्भुत होगा, जैसे कुछ (http://stackoverflow.com/a/12074451) http://jsfiddle.net/neoswf/aXzWw/ या jsperf .com – SDK

-2
var a = {a:'a1',b:'b1'}, 
    b = {a:'a2',b:'b2',c:'c2'}; 

_.pick(a,_.intersection(_.keys(a),_.keys(b))); 

// {a:'a1',b:'b1'} 
+1

यह गलत है, तुलना केवल कुंजी पर की जाती है: _.keys (ए) रिटर्न ["ए", "बी"] और _.keys (बी) रिटर्न ["ए", "बी", " सी"]। –

0

आप चाहते हैं केवल तुलना वस्तुओं:

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' } } 
3

lodash 4.0.0 में। हम इस

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

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

आउटपुट की तरह की कोशिश कर सकते हैं:

[{ 'आईडी': 1, 'नाम': 'जेक'}];

+0

हां, इन दिनों नवीनतम लॉनाश के साथ बहुत आसान है! – Rodney

+0

अंत में अंडरस्कोर से लोनाश में स्विच करने जा रहा है – claytronicon

संबंधित मुद्दे