जावास्क्रिप्ट में दो सरणियों के बीच अंतर कैसे प्राप्त करें?


751

क्या जावास्क्रिप्ट में दो सरणियों के बीच अंतर को वापस करने का एक तरीका है?

उदाहरण के लिए:

var a1 = ['a', 'b'];
var a2 = ['a', 'b', 'c', 'd'];

// need ["c", "d"]

9
सममित या गैर-सममित?
हल्की दौड़ ऑर्बिट

नए ईएस 6 फ़ंक्शन के साथ यह एक साधारण एक लाइनर के रूप में किया जा सकता है (सभी अन्य ब्राउज़र में उपयोग करने में सक्षम होने में बहुत समय लगेगा)। किसी भी मामले में मेरे जवाब की
सल्वाडोर डाली

1
समाधान का एक महत्वपूर्ण पहलू प्रदर्शन है। इस प्रकार के ऑपरेशन की असममित समय जटिलता - अन्य भाषाओं में - क्या O(a1.length x log(a2.length))- यह प्रदर्शन जावास्क्रिप्ट में संभव है?
राउल

जवाबों:


218

मुझे लगता है कि आप एक सामान्य सरणी की तुलना कर रहे हैं। यदि नहीं, तो आप को बदलने की जरूरत के लिए पाश एक करने के लिए में .. के लिए पाश।

function arr_diff (a1, a2) {

    var a = [], diff = [];

    for (var i = 0; i < a1.length; i++) {
        a[a1[i]] = true;
    }

    for (var i = 0; i < a2.length; i++) {
        if (a[a2[i]]) {
            delete a[a2[i]];
        } else {
            a[a2[i]] = true;
        }
    }

    for (var k in a) {
        diff.push(k);
    }

    return diff;
}

console.log(arr_diff(['a', 'b'], ['a', 'b', 'c', 'd']));
console.log(arr_diff("abcd", "abcde"));
console.log(arr_diff("zxc", "zxc"));

एक बेहतर समाधान, यदि आप पिछड़े संगतता के बारे में परवाह नहीं करते हैं, तो फिल्टर का उपयोग कर रहा है। लेकिन फिर भी, यह समाधान काम करता है।


46
यह काम कर सकता है लेकिन यह तीन लूपों को पूरा करने के लिए करता है जो एरे की फिल्टर विधि का उपयोग करके कोड की एक पंक्ति में किया जा सकता है।
जोशवेन पॉटर

9
बस स्पष्ट होने के लिए, यह यहाँ पोस्ट किए गए अन्य उत्तरों के विपरीत, a1 और a2 के सममित अंतर को लागू करता है।
200_success

25
यह सबसे अच्छा उत्तर नहीं है, लेकिन मैं इसे अनुचित चढ़ाव के लिए बनाने में मदद करने के लिए एक चैरिटी अपवोट दे रहा हूं। केवल गलत उत्तरों को अस्वीकृत किया जाना चाहिए, और अगर मैं किसी प्रोजेक्ट पर cruft-browser के साथ काम कर रहा हूं, तो यह मुश्किल भी हो सकता है।
माइकल स्काइपर

3
क्या पता कब var a1 = ['a', 'b'];और क्या हो जाए var a2 = ['a', 'b', 'c', 'd', 'b'];, यह गलत उत्तर लौटाएगा , अर्थात ['c', 'd', 'b']इसके बजाय ['c', 'd']
skbly7

4
सबसे तेज़ तरीका सबसे स्पष्ट रूप से भोला समाधान है। मैंने इस थ्रेड में सममित function diff2(a, b) { var i, la = a.length, lb = b.length, res = []; if (!la) return b; else if (!lb) return a; for (i = 0; i < la; i++) { if (b.indexOf(a[i]) === -1) res.push(a[i]); } for (i = 0; i < lb; i++) { if (a.indexOf(b[i]) === -1) res.push(b[i]); } return res; }
भिन्नता के

1222

ES7 का उपयोग करने का एक बेहतर तरीका है:


चौराहा

 let intersection = arr1.filter(x => arr2.includes(x));

अंतर अंतर वेन आरेख

इसके लिए [1,2,3] [2,3]उपज होगी [2,3]। दूसरी ओर, [1,2,3] [2,3,5]उसी चीज को वापस करेगा।


अंतर

let difference = arr1.filter(x => !arr2.includes(x));

सही अंतर वेन आरेख

इसके लिए [1,2,3] [2,3]उपज होगी [1]। दूसरी ओर, [1,2,3] [2,3,5]उसी चीज को वापस करेगा।


एक सममित अंतर के लिए , आप कर सकते हैं:

let difference = arr1
                 .filter(x => !arr2.includes(x))
                 .concat(arr2.filter(x => !arr1.includes(x)));

सममित अंतर वेन आरेख

इस तरह, आपको एरी 1 के सभी तत्वों से युक्त एक सरणी मिलेगी जो एरे 2 और इसके विपरीत नहीं है

जैसा कि @ जोशेन पॉटर ने अपने जवाब में बताया, आप इसे Array.prototype में जोड़ सकते हैं ताकि इसे इस तरह बनाया जा सके:

Array.prototype.diff = function(arr2) { return this.filter(x => !arr2.includes(x)); }
[1, 2, 3].diff([2, 3])

3
मैं < 0इसके बजाय की जाँच करना पसंद करता हूँ== -1
विक

1
Arrayअंतर को समझना एक तथाकथित है set operation, क्योंकि संपत्ति की खोज एस का बहुत ही काम है Set, जो कि तब तीव्रता के आदेश हैं indexOf/ includes। सीधे शब्दों में कहें, तो आपका समाधान बहुत ही अक्षम और धीमा है।

@ आफ़्टर लेकिन Set, मूल्यों के लिए अद्वितीय होना चाहिए, नहीं?
CervEd

1
@LuisSieira मुझे लगता है कि यह काम करने के लिए होगा [1,2,3] [2,3,5]कि नंबर अद्वितीय हैं लेकिन अगर आपने कहा था [1,1,2,3] [1,2,3,5]और उम्मीद है कि [1]आप उपयोग नहीं कर सकते Set। हालांकि आपका समाधान या तो काम नहीं करेगा: - / मैंने इस फ़ंक्शन को बनाना समाप्त कर दिया है क्योंकि मैं इसे अधिक सफलतापूर्वक करने के लिए एक संतोषजनक तरीके का पता नहीं लगा सका। यदि आपके पास ऐसा करने के बारे में कोई विचार है, तो मुझे जानना अच्छा लगेगा!
सर्वाइड

3
Array.includes()ES6 की जगह ES7 फीचर नहीं है ? (1) (2) - और जारी रखने के लिए, ES6 के साथ आप Array.some()उदाहरण के लिए इस्तेमाल कर सकते हैं let intersection = aArray.filter(a => bArray.some(b => a === b)), नहीं?
जरी कीनेलेन

910
Array.prototype.diff = function(a) {
    return this.filter(function(i) {return a.indexOf(i) < 0;});
};

////////////////////  
// Examples  
////////////////////

[1,2,3,4,5,6].diff( [3,4,5] );  
// => [1, 2, 6]

["test1", "test2","test3","test4","test5","test6"].diff(["test1","test2","test3","test4"]);  
// => ["test5", "test6"]

नोट इंडेक्सऑफ और फिल्टर आईई 9 से पहले उपलब्ध नहीं हैं।


50
एकमात्र ब्राउज़र जो मायने रखता है जो फ़िल्टर और इंडेक्सऑफ़ का समर्थन नहीं करता है IE8 है। IE9 उन दोनों का समर्थन करता है। तो यह गलत नहीं है।
ब्रायन लार्सन

14
IE7 और IE8 अभी भी (दुर्भाग्य से) बहुत ही प्रासंगिक है, तथापि आप MDN साइट पर दोनों कार्यों के लिए polyfill कोड प्राप्त कर सकते हैं: developer.mozilla.org/en/JavaScript/Reference/Global_Objects/... developer.mozilla.org/en/JavaScript/ संदर्भ / Global_Objects /… एक IE सशर्त और BOOM के माध्यम से "संगतता" के तहत सूचीबद्ध कोड में लोड करें। Ie7 / 8 समर्थित हैं।
1nfiniti

44
इस समाधान में O (n ^ 2) का रन समय है एक रैखिक समाधान कहीं अधिक कुशल होगा।
झोलमन

75
यदि आप इस तरह से फ़ंक्शन का उपयोग करते हैं: तो यह बदले में [1,2,3].diff([3,4,5])वापस आ [1,2]जाएगा, [1,2,4,5]इसलिए यह मूल प्रश्न में समस्या को हल नहीं करता है, कुछ के बारे में पता होना चाहिए।
बुगस्टर

12
@AlinPurcaru पुरातन ब्राउज़रों द्वारा समर्थित नहीं है! = गलत है। नेटस्केप 2.0 को ध्यान में रखते हुए, जेएस कोड का अधिकांश भाग इस परिभाषा के अनुसार "गलत" है। यह कहना एक मूर्खतापूर्ण बात है।
NullUserException

304

यह अब तक का सबसे आसान तरीका है जिससे आप जिस परिणाम की तलाश कर रहे हैं, वह jQuery का उपयोग कर रहा है:

var diff = $(old_array).not(new_array).get();

diffअब इसमें वह है जो इसमें old_arrayनहीं थाnew_array


4
@ बाथमैन हां, लेकिन केवल अगर वे एक ही वस्तु ( {a: 1} != {a: 1}) ( प्रमाण ) के संदर्भ में हैं
Matmarbon

क्या कस्टम ऑब्जेक्ट के डेटा को रखने वाले सरणियों के साथ इसका उपयोग करना संभव है? मैं वास्तव में उसी तरह की कोशिश की, लेकिन यह काम नहीं किया। कोई भी विचार अत्यधिक प्रशंसनीय होगा।
LetMeCode आप

8
क्या यह एक चाल है? दस्तावेज़ के भाग के रूप में मानता है इस विधि DOM एलीमेंट के तरीके और नहीं एक सामान्य सरणी सहायक के रूप में। तो यह अब इस तरह से काम कर सकता है, लेकिन शायद भविष्य के संस्करणों में नहीं, क्योंकि इस तरह से इसका उपयोग करने का इरादा नहीं था। हालांकि, मुझे खुशी होगी अगर यह आधिकारिक तौर पर एक सामान्य सरणी सहायक होगा।
रॉब्सच

1
@robsch जब आप .notकिसी सरणी के साथ उपयोग करते हैं, तो jQuery इसका उपयोग करता है .grep()जो अंतर्निहित उपयोगिता है जो विशेष रूप से फ़िल्टरिंग सरणियों के लिए है। मैं इसे बदलते नहीं देख सकता।
सुपरऑफोनिक

1
@vsync ध्वनि की तरह आप एक सममित अंतर के बाद कर रहे हैं
superphonic

158

अंडरस्कोर में अंतर विधि (या इसके ड्रॉप-इन प्रतिस्थापन, लो-डैश ) भी ऐसा कर सकते हैं:

(R)eturns the values from array that are not present in the other arrays

_.difference([1, 2, 3, 4, 5], [5, 2, 10]);
=> [1, 3, 4]

किसी भी अंडरस्कोर फ़ंक्शन के साथ, आप इसे अधिक ऑब्जेक्ट-ओरिएंटेड शैली में भी उपयोग कर सकते हैं:

_([1, 2, 3, 4, 5]).difference([5, 2, 10]);

4
मुझे लगता है कि यह एक अच्छा समाधान प्रदर्शन-वार है, विशेष रूप से लॉश और अंडरस्कोर सर्वोत्तम कार्यान्वयन के लिए जूझते रहते हैं। इसके अलावा, यह IE6- संगत है।
Mahemoff

4
खबरदार, यह कार्यान्वयन वस्तुओं के सरणियों के लिए काम नहीं करेगा। अधिक जानकारी के लिए stackoverflow.com/q/8672383/14731 देखें ।
गिल्ली

1
जैसा कि एक उत्तर में उल्लेख है, यह काम करता है यदि यह एक ही वस्तु है, लेकिन नहीं अगर दो वस्तुओं में समान गुण हैं। मुझे लगता है कि समानता की धारणा अलग-अलग है (जैसे कि यह कुछ ऐप्स में "आईडी" विशेषता भी हो सकती है)। हालांकि, यह अच्छा होगा यदि आप एक तुलना परीक्षण में पास कर सकते हैं ()।
Mahemoff

पोस्टरिटी के लिए: लोदश में अब _.differenceBy () है जो तुलना करने के लिए कॉलबैक लेता है; यदि आप उन वस्तुओं की तुलना कर रहे हैं जिन्हें आप किसी ऐसे फ़ंक्शन में छोड़ सकते हैं जो आपकी ज़रूरत की तुलना में है।
SomeCallMeTim 21

2
सावधान रहें यदि तर्कों का क्रम उलट गया, तो यह काम नहीं करेगा। जैसे। _.difference ([5, 2, 10], [1, 2, 3, 4, 5]); अंतर प्राप्त नहीं कर सकते हैं
Russj

79

सादा जावास्क्रिप्ट

"अंतर" के लिए दो संभावित अंतर्ग्रहण हैं। मैं आपको वह चुनने दूंगा जो आप चाहते हैं। आप कहें:

var a1 = ['a', 'b'     ];
var a2 = [     'b', 'c'];
  1. यदि आप प्राप्त करना चाहते हैं ['a'], तो इस फ़ंक्शन का उपयोग करें:

    function difference(a1, a2) {
      var result = [];
      for (var i = 0; i < a1.length; i++) {
        if (a2.indexOf(a1[i]) === -1) {
          result.push(a1[i]);
        }
      }
      return result;
    }
  2. यदि आप प्राप्त करना चाहते हैं ['a', 'c'](सभी तत्व या तो निहित हैं , लेकिन दोनों नहीं - तथाकथित सममित अंतर ), इस फ़ंक्शन का उपयोग करें:a1a2

    function symmetricDifference(a1, a2) {
      var result = [];
      for (var i = 0; i < a1.length; i++) {
        if (a2.indexOf(a1[i]) === -1) {
          result.push(a1[i]);
        }
      }
      for (i = 0; i < a2.length; i++) {
        if (a1.indexOf(a2[i]) === -1) {
          result.push(a2[i]);
        }
      }
      return result;
    }

लोदाश / अंडरस्कोर

यदि आप लॉश का उपयोग कर रहे हैं, तो आप _.difference(a1, a2)(ऊपर केस 1) या _.xor(a1, a2)(केस 2) का उपयोग कर सकते हैं ।

यदि आप Underscore.js का उपयोग कर रहे हैं, तो आप उपयोग कर सकते हैं _.difference(a1, a2) केस 1 के लिए फ़ंक्शन का ।

ES6 सेट, बहुत बड़ी सरणियों के लिए

उपरोक्त कोड सभी ब्राउज़रों पर काम करता है। हालांकि, लगभग 10,000 से अधिक वस्तुओं के बड़े सरणियों के लिए, यह काफी धीमा हो जाता है, क्योंकि इसमें O (n²) जटिलता है। कई आधुनिक ब्राउज़रों पर, हम Setचीजों को गति देने के लिए ES6 ऑब्जेक्ट का लाभ उठा सकते हैं । Setउपलब्ध होने पर लोडश स्वचालित रूप से उपयोग करता है। यदि आप लॉश का उपयोग नहीं कर रहे हैं, तो एक्सल रौशमेयर के ब्लॉग पोस्ट से प्रेरित होकर निम्नलिखित कार्यान्वयन का उपयोग करें :

function difference(a1, a2) {
  var a2Set = new Set(a2);
  return a1.filter(function(x) { return !a2Set.has(x); });
}

function symmetricDifference(a1, a2) {
  return difference(a1, a2).concat(difference(a2, a1));
}

टिप्पणियाँ

यदि आप -0, +0, NaN या विरल सरणियों की परवाह करते हैं तो सभी उदाहरणों के लिए व्यवहार आश्चर्यजनक या गैर-स्पष्ट हो सकता है । (अधिकांश उपयोगों के लिए, यह कोई मायने नहीं रखता है।)


धन्यवाद। आपने मेरा दिन बचाया। मुझे 300K सरणियों की तुलना करनी थी, और आपके "सेट" समाधान ने पूरी तरह से काम किया। यह स्वीकृत उत्तर होना चाहिए।
जस्टदेव

52

सममित अंतर प्राप्त करने के लिए आपको दोनों तरीकों से सरणियों की तुलना करने की आवश्यकता है (या कई सरणियों के मामले में सभी तरीकों से)

यहां छवि विवरण दर्ज करें


ES7 (ECMAScript 2016)

// diff between just two arrays:
function arrayDiff(a, b) {
    return [
        ...a.filter(x => !b.includes(x)),
        ...b.filter(x => !a.includes(x))
    ];
}

// diff between multiple arrays:
function arrayDiff(...arrays) {
    return [].concat(...arrays.map( (arr, i) => {
        const others = arrays.slice(0);
        others.splice(i, 1);
        const unique = [...new Set([].concat(...others))];
        return arr.filter(x => !unique.includes(x));
    }));
}

ईएस 6 (ईसीएमएस्क्रिप्ट 2015)

// diff between just two arrays:
function arrayDiff(a, b) {
    return [
        ...a.filter(x => b.indexOf(x) === -1),
        ...b.filter(x => a.indexOf(x) === -1)
    ];
}

// diff between multiple arrays:
function arrayDiff(...arrays) {
    return [].concat(...arrays.map( (arr, i) => {
        const others = arrays.slice(0);
        others.splice(i, 1);
        const unique = [...new Set([].concat(...others))];
        return arr.filter(x => unique.indexOf(x) === -1);
    }));
}

ES5 (ECMAScript 5.1)

// diff between just two arrays:
function arrayDiff(a, b) {
    var arrays = Array.prototype.slice.call(arguments);
    var diff = [];

    arrays.forEach(function(arr, i) {
        var other = i === 1 ? a : b;
        arr.forEach(function(x) {
            if (other.indexOf(x) === -1) {
                diff.push(x);
            }
        });
    })

    return diff;
}

// diff between multiple arrays:
function arrayDiff() {
    var arrays = Array.prototype.slice.call(arguments);
    var diff = [];

    arrays.forEach(function(arr, i) {
        var others = arrays.slice(0);
        others.splice(i, 1);
        var otherValues = Array.prototype.concat.apply([], others);
        var unique = otherValues.filter(function (x, j) { 
            return otherValues.indexOf(x) === j; 
        });
        diff = diff.concat(arr.filter(x => unique.indexOf(x) === -1));
    });
    return diff;
}

उदाहरण:

// diff between two arrays:
const a = ['a', 'd', 'e'];
const b = ['a', 'b', 'c', 'd'];
arrayDiff(a, b); // (3) ["e", "b", "c"]

// diff between multiple arrays
const a = ['b', 'c', 'd', 'e', 'g'];
const b = ['a', 'b'];
const c = ['a', 'e', 'f'];
arrayDiff(a, b, c); // (4) ["c", "d", "g", "f"]

वस्तुओं के Arrays के बीच अंतर

function arrayDiffByKey(key, ...arrays) {
    return [].concat(...arrays.map( (arr, i) => {
        const others = arrays.slice(0);
        others.splice(i, 1);
        const unique = [...new Set([].concat(...others))];
        return arr.filter( x =>
            !unique.some(y => x[key] === y[key])
        );
    }));
}

उदाहरण:

const a = [{k:1}, {k:2}, {k:3}];
const b = [{k:1}, {k:4}, {k:5}, {k:6}];
const c = [{k:3}, {k:5}, {k:7}];
arrayDiffByKey('k', a, b, c); // (4) [{k:2}, {k:4}, {k:6}, {k:7}]

49

ES6 में एक क्लीनर दृष्टिकोण निम्नलिखित समाधान है।

var a1 = ['a', 'b'];
var a2 = ['a', 'b', 'c', 'd'];

अंतर

a2.filter(d => !a1.includes(d)) // gives ["c", "d"]

चौराहा

a2.filter(d => a1.includes(d)) // gives ["a", "b"]

विघटनकारी संघ (सममित अंतर)

[ ...a2.filter(d => !a1.includes(d)),
  ...a1.filter(d => !a2.includes(d)) ]

यह केवल एक दिशा में काम करता है। अब कल्पना कीजिए कि a1 = ['a', 'b', 'e']: निकाला नहीं जाएगा।
imrok

हां, यह है कि सेट सिद्धांत में अंतर कैसे काम करता है। (a2 -a1) आप जो ढूंढ रहे हैं (a-a1) + (a1-a2)
ifelse.codes

1
@imrok मेरा मानना ​​है कि यह वही है जो आप देख रहे हैं [... a2.filter (d =>! a1.includes (d)), ... (a1.filter (d =>! a2.includes (d))) )]
ifelse.codes

2
सुंदर समाधान, धन्यवाद!
थियागो

40

आप इस मामले में एक सेट का उपयोग कर सकते हैं । यह इस तरह के ऑपरेशन (संघ, चौराहे, अंतर) के लिए अनुकूलित है।

सुनिश्चित करें कि यह आपके मामले पर लागू होता है, एक बार यह कोई डुप्लिकेट की अनुमति नहीं देता है।

var a = new JS.Set([1,2,3,4,5,6,7,8,9]);
var b = new JS.Set([2,4,6,8]);

a.difference(b)
// -> Set{1,3,5,7,9}

4
यह एक अच्छा पुस्तकालय की तरह लग रहा है! क्या शर्म की बात है कि आप Setसब कुछ पाने के लिए सिर्फ फ़ंक्शन डाउनलोड नहीं कर सकते ...
ब्लिक्स

@ विश्वास मुझे विश्वास है कि आप इसे डाउनलोड कर सकते हैं, और बस सेट को शामिल कर सकते हैं। जेएस फाइल
सैमुएल कैरिजो

सेट को गूगल क्लोजर में भी लागू किया जाता है। Closeure-library.googlecode.com/svn/docs/…
बेन फ्लिन


32
function diff(a1, a2) {
  return a1.concat(a2).filter(function(val, index, arr){
    return arr.indexOf(val) === arr.lastIndexOf(val);
  });
}

दोनों सरणियों को मर्ज करें, अद्वितीय मान केवल एक बार दिखाई देंगे ताकि इंडेक्सऑफ () लास्टइंडेक्सऑफ () के समान हो।


3
मैं मानता हूं कि यह सबसे साफ और सरल तरीका है और अच्छा है कि इसके लिए प्रोटोटाइप को छूने की आवश्यकता नहीं है। "अगर आप इसे छह साल की उम्र में नहीं समझा सकते हैं, तो आप इसे खुद नहीं समझ सकते।" - अल्बर्ट आइंस्टीन
लैकोस्टेनकोडर 18

18

एक सरणी को दूसरे से घटाने के लिए, बस नीचे दिए गए स्निपेट का उपयोग करें:

var a1 = ['1','2','3','4','6'];
var a2 = ['3','4','5'];

var items = new Array();

items = jQuery.grep(a1,function (item) {
    return jQuery.inArray(item, a2) < 0;
});

यह ['1,' 2 ',' 6 '] लौटाएगा, जो पहले एरे के आइटम हैं जो दूसरे में मौजूद नहीं हैं।

इसलिए, आपकी समस्या के नमूने के अनुसार, निम्नलिखित कोड सटीक समाधान है:

var array1 = ["test1", "test2","test3", "test4"];
var array2 = ["test1", "test2","test3","test4", "test5", "test6"];

var _array = new Array();

_array = jQuery.grep(array2, function (item) {
     return jQuery.inArray(item, array1) < 0;
});

14

ES6 के सेट और फाटक ऑपरेटर के साथ आने के साथ (केवल फ़ायरफ़ॉक्स में काम करता है, संगतता तालिका की जाँच करें ), आप निम्नलिखित एक लाइनर लिख सकते हैं:

var a = ['a', 'b', 'c', 'd'];
var b = ['a', 'b'];
var b1 = new Set(b);
var difference = [...new Set([...a].filter(x => !b1.has(x)))];

जिसके परिणामस्वरूप होगा [ "c", "d" ]


बस जिज्ञासु यह है कि ऐसा करने से कोई अलग कैसे हैb.filter(x => !a.indexOf(x)))
chovy

1
@chovy यह समय जटिलता में अलग है। मेरा समाधान है O(n + m)आपका समाधान वह O(n * m)जगह है जहाँ n और m लम्बाई के सरणियाँ हैं। लंबी सूची लें और मेरा समाधान सेकंड में चलेगा, जबकि आपका समय लगेगा।
साल्वाडोर डाली

वस्तुओं की सूची की विशेषता की तुलना करने के बारे में क्या? क्या इस समाधान का उपयोग करना संभव है?
चॉवी

2
a.filter(x => !b1.has(x))सरल है। और ध्यान दें कि कल्पना को केवल औसत के n * f(m) + mसाथ जटिलता की आवश्यकता होती है f(m)। यह बेहतर है n * m, लेकिन जरूरी नहीं है n + m
उड़ोल

2
@SalvadorDali var difference = [...new Set([...a].filter(x => !b1.has(x)))];आप डुप्लिकेट 'ए' सरणी क्यों बना रहे हैं? आप एक सेट में फ़िल्टर का परिणाम क्यों बदल रहे हैं और फिर वापस सरणी में हैं? इस के बराबर नहीं हैvar difference = a.filter(x => !b1.has(x));
दीपक मित्तल

13

ES2015 के साथ कार्यात्मक दृष्टिकोण

differenceदो सरणियों के बीच कम्प्यूटिंग Setसंचालन में से एक है । शब्द पहले से ही इंगित करता है कि Setलुकअप की गति को बढ़ाने के लिए देशी प्रकार का उपयोग किया जाना चाहिए। वैसे भी, जब आप दो सेटों के बीच अंतर की गणना करते हैं तो तीन क्रमांकन होते हैं:

[+left difference] [-intersection] [-right difference]
[-left difference] [-intersection] [+right difference]
[+left difference] [-intersection] [+right difference]

यहाँ एक कार्यात्मक समाधान है जो इन क्रमपरिवर्तन को दर्शाता है।

वाम difference:

// small, reusable auxiliary functions

const apply = f => x => f(x);
const flip = f => y => x => f(x) (y);
const createSet = xs => new Set(xs);
const filter = f => xs => xs.filter(apply(f));


// left difference

const differencel = xs => ys => {
  const zs = createSet(ys);
  return filter(x => zs.has(x)
     ? false
     : true
  ) (xs);
};


// mock data

const xs = [1,2,2,3,4,5];
const ys = [0,1,2,3,3,3,6,7,8,9];


// run the computation

console.log( differencel(xs) (ys) );

अधिकार difference:

differencerतुच्छ है। यह सिर्फ differencelफ़्लिप तर्कों के साथ है। आप सुविधा के लिए एक फ़ंक्शन लिख सकते हैं:const differencer = flip(differencel) :। बस इतना ही!

सममित difference:

अब जबकि हमारे पास बाएँ और दाएँ एक है, सममित differenceको लागू करने से तुच्छ हो जाता है:

// small, reusable auxiliary functions

const apply = f => x => f(x);
const flip = f => y => x => f(x) (y);
const concat = y => xs => xs.concat(y);
const createSet = xs => new Set(xs);
const filter = f => xs => xs.filter(apply(f));


// left difference

const differencel = xs => ys => {
  const zs = createSet(ys);
  return filter(x => zs.has(x)
     ? false
     : true
  ) (xs);
};


// symmetric difference

const difference = ys => xs =>
 concat(differencel(xs) (ys)) (flip(differencel) (xs) (ys));

// mock data

const xs = [1,2,2,3,4,5];
const ys = [0,1,2,3,3,3,6,7,8,9];


// run the computation

console.log( difference(xs) (ys) );

मुझे लगता है कि इस उदाहरण को एक छाप प्राप्त करने के लिए एक अच्छा प्रारंभिक बिंदु है जो कार्यात्मक प्रोग्रामिंग का मतलब है:

बिल्डिंग ब्लॉक्स के साथ प्रोग्रामिंग जो कई अलग-अलग तरीकों से एक साथ प्लग की जा सकती है।


12

एक समाधान का उपयोग indexOf()छोटे सरणियों के लिए ठीक होगा लेकिन जब वे लंबाई में बढ़ते हैं तो एल्गोरिथ्म दृष्टिकोण का प्रदर्शन होता है O(n^2)। यहां एक समाधान है जो ऑब्जेक्ट्स को कुंजी के रूप में संग्रहीत करने के लिए साहचर्य सरणियों के रूप में वस्तुओं का उपयोग करके बहुत बड़ी सरणियों के लिए बेहतर प्रदर्शन करेगा; यह डुप्लिकेट प्रविष्टियों को स्वचालित रूप से समाप्त कर देता है लेकिन केवल स्ट्रिंग मानों (या मान जो सुरक्षित रूप से स्ट्रिंग्स के रूप में संग्रहीत किए जा सकते हैं) के साथ काम करता है:

function arrayDiff(a1, a2) {
  var o1={}, o2={}, diff=[], i, len, k;
  for (i=0, len=a1.length; i<len; i++) { o1[a1[i]] = true; }
  for (i=0, len=a2.length; i<len; i++) { o2[a2[i]] = true; }
  for (k in o1) { if (!(k in o2)) { diff.push(k); } }
  for (k in o2) { if (!(k in o1)) { diff.push(k); } }
  return diff;
}

var a1 = ['a', 'b'];
var a2 = ['a', 'b', 'c', 'd'];
arrayDiff(a1, a2); // => ['c', 'd']
arrayDiff(a2, a1); // => ['c', 'd']

जब भी आप किसी ऑब्जेक्ट पर "के लिए" कर रहे हों, तो आप Object.hasOwnProperty () का उपयोग करना चाहते हैं। अन्यथा आप डिफ़ॉल्ट ऑब्जेक्ट के प्रोटोटाइप में जोड़े गए प्रत्येक फ़ील्ड के माध्यम से लूपिंग का जोखिम चलाते हैं। (या सिर्फ अपनी वस्तु के माता-पिता) इसके अलावा आपको केवल दो छोरों की जरूरत है, एक हैश टेबल निर्माण के लिए, और दूसरा उस हैश टेबल पर दिखता है।
झोलोमन

1
@ झोलमोन मैं सम्मानपूर्वक असहमत हूं । अब जब हम किसी भी संपत्ति के लिए गणना करने योग्यता को नियंत्रित कर सकते हैं, तो संभवतः आपको किसी भी संपत्ति को शामिल किया जाना चाहिए जो आपको गणना के दौरान मिलती है।
फ्रॉग्ज

1
@Phrogz एक अच्छा बिंदु यदि आप केवल आधुनिक ब्राउज़रों के बारे में चिंतित हैं। दुर्भाग्य से मुझे काम पर IE7 का समर्थन करना है इसलिए पत्थर की उम्र मेरे विचार की डिफ़ॉल्ट ट्रेन है और हम शिम का उपयोग नहीं करते हैं।
झूलोमन

10

जोशवेन पॉटर द्वारा उपरोक्त उत्तर महान है। लेकिन यह सरणी B में ऐसे तत्व देता है जो सरणी C में नहीं हैं, लेकिन दूसरे तरीके से नहीं। उदाहरण के लिए, यदि var a=[1,2,3,4,5,6].diff( [3,4,5,7]);यह आउटपुट करेगा: ==> [1,2,6], लेकिन नहीं [1,2,6,7] , जो कि दोनों के बीच वास्तविक अंतर है। आप अभी भी पॉटर कोड का उपयोग कर सकते हैं, लेकिन बस एक बार पीछे की तुलना की तुलना करें:

Array.prototype.diff = function(a) {
    return this.filter(function(i) {return !(a.indexOf(i) > -1);});
};

////////////////////  
// Examples  
////////////////////

var a=[1,2,3,4,5,6].diff( [3,4,5,7]);
var b=[3,4,5,7].diff([1,2,3,4,5,6]);
var c=a.concat(b);
console.log(c);

यह आउटपुट चाहिए: [ 1, 2, 6, 7 ]


9

समस्या को हल करने का दूसरा तरीका

function diffArray(arr1, arr2) {
    return arr1.concat(arr2).filter(function (val) {
        if (!(arr1.includes(val) && arr2.includes(val)))
            return val;
    });
}

diffArray([1, 2, 3, 7], [3, 2, 1, 4, 5]);    // return [7, 4, 5]

इसके अलावा, आप तीर फ़ंक्शन सिंटैक्स का उपयोग कर सकते हैं:

const diffArray = (arr1, arr2) => arr1.concat(arr2)
    .filter(val => !(arr1.includes(val) && arr2.includes(val)));

diffArray([1, 2, 3, 7], [3, 2, 1, 4, 5]);    // return [7, 4, 5]

7
Array.prototype.difference = function(e) {
    return this.filter(function(i) {return e.indexOf(i) < 0;});
};

eg:- 

[1,2,3,4,5,6,7].difference( [3,4,5] );  
 => [1, 2, 6 , 7]

आपको कभी भी इस तरह से एक देशी वस्तु का विस्तार नहीं करना चाहिए। यदि मानक differenceभविष्य के संस्करण में फ़ंक्शन के रूप में परिचय देता है और इस फ़ंक्शन का फिर एक अलग फ़ंक्शन हस्ताक्षर होता है तो आपका, यह आपके कोड या विदेशी पुस्तकालयों को तोड़ देगा जो इस फ़ंक्शन का उपयोग करते हैं।
t.niese

7

जावास्क्रिप्ट के फिल्टर फ़ंक्शन के साथ बहुत सरल समाधान:

var a1 = ['a', 'b'];
var a2 = ['a', 'b', 'c', 'd'];

function diffArray(arr1, arr2) {
  var newArr = [];
  var myArr = arr1.concat(arr2);
  
    newArr = myArr.filter(function(item){
      return arr2.indexOf(item) < 0 || arr1.indexOf(item) < 0;
    });
   alert(newArr);
}

diffArray(a1, a2);


6

इस बारे में कैसा है:

Array.prototype.contains = function(needle){
  for (var i=0; i<this.length; i++)
    if (this[i] == needle) return true;

  return false;
} 

Array.prototype.diff = function(compare) {
    return this.filter(function(elem) {return !compare.contains(elem);})
}

var a = new Array(1,4,7, 9);
var b = new Array(4, 8, 7);
alert(a.diff(b));

तो इस तरह से आप array1.diff(array2)उनके अंतर को प्राप्त कर सकते हैं (एल्गोरिथम के लिए भयानक समय जटिलता हालांकि - ओ (array1.length x array2.length) मेरा मानना ​​है)


फ़िल्टर विकल्प का उपयोग करना एक महान विचार है ... हालाँकि, आपको ऐरे के लिए एक विधि बनाने की आवश्यकता नहीं है। मैंने आपके विचार को एक लाइनर में बदल दिया ... प्रेरणा के लिए धन्यवाद!
जोशवेन पॉटर

आपको फ़ंक्शन () फ़ंक्शन को परिभाषित करने की आवश्यकता नहीं है। जेएस भी शामिल () करता है।
दा मैन

4

Http://phrogz.net/JS/ArraySetMath.js का उपयोग करके आप कर सकते हैं:

var array1 = ["test1", "test2","test3", "test4"];
var array2 = ["test1", "test2","test3","test4", "test5", "test6"];

var array3 = array2.subtract( array1 );
// ["test5", "test6"]

var array4 = array1.exclusion( array2 );
// ["test5", "test6"]

4
function diffArray(arr1, arr2) {
  var newArr = arr1.concat(arr2);
  return newArr.filter(function(i){
    return newArr.indexOf(i) == newArr.lastIndexOf(i);
  });
}

यह मेरे लिए काम करता है


3
  • शुद्ध जावास्क्रिप्ट समाधान (कोई लाइब्रेरी नहीं)
  • पुराने ब्राउज़रों के साथ संगत (उपयोग नहीं करता है filter)
  • O (n ^ 2)
  • वैकल्पिक fnकॉलबैक पैरामीटर जो आपको निर्दिष्ट करता है कि सरणी आइटम की तुलना कैसे करें

function diff(a, b, fn){
    var max = Math.max(a.length, b.length);
        d = [];
    fn = typeof fn === 'function' ? fn : false
    for(var i=0; i < max; i++){
        var ac = i < a.length ? a[i] : undefined
            bc = i < b.length ? b[i] : undefined;
        for(var k=0; k < max; k++){
            ac = ac === undefined || (k < b.length && (fn ? fn(ac, b[k]) : ac == b[k])) ? undefined : ac;
            bc = bc === undefined || (k < a.length && (fn ? fn(bc, a[k]) : bc == a[k])) ? undefined : bc;
            if(ac == undefined && bc == undefined) break;
        }
        ac !== undefined && d.push(ac);
        bc !== undefined && d.push(bc);
    }
    return d;
}

alert(
    "Test 1: " + 
    diff(
        [1, 2, 3, 4],
        [1, 4, 5, 6, 7]
      ).join(', ') +
    "\nTest 2: " +
    diff(
        [{id:'a',toString:function(){return this.id}},{id:'b',toString:function(){return this.id}},{id:'c',toString:function(){return this.id}},{id:'d',toString:function(){return this.id}}],
        [{id:'a',toString:function(){return this.id}},{id:'e',toString:function(){return this.id}},{id:'f',toString:function(){return this.id}},{id:'d',toString:function(){return this.id}}],
        function(a, b){ return a.id == b.id; }
    ).join(', ')
);


आप कुछ और गति निचोड़ने के लिए लंबाई मानों को कैश कर सकते हैं। मैं लंबाई के लिए जाँच किए बिना ऐरे तत्वों तक पहुँचने की सलाह देना चाहता था, लेकिन जाहिर है कि साधारण जाँच से लगभग 100 गुना स्पीडअप मिलता है।
स्लोटोस

lengthमूल्यों को कैश करने का कोई कारण नहीं । यह पहले से ही सादे संपत्ति है। jsperf.com/array-length-caching
vp_arth

3

यह काम कर रहा है: मूल रूप से दो सरणियों को मर्ज करें, डुप्लिकेट की तलाश करें और जो एक नए सरणी में अंतर नहीं है, उसे दोहराएं।

function diff(arr1, arr2) {
  var newArr = [];
  var arr = arr1.concat(arr2);
  
  for (var i in arr){
    var f = arr[i];
    var t = 0;
    for (j=0; j<arr.length; j++){
      if(arr[j] === f){
        t++; 
        }
    }
    if (t === 1){
      newArr.push(f);
        }
  } 
  return newArr;
}


3

// es6 दृष्टिकोण

function diff(a, b) {
  var u = a.slice(); //dup the array
  b.map(e => {
    if (u.indexOf(e) > -1) delete u[u.indexOf(e)]
    else u.push(e)   //add non existing item to temp array
  })
  return u.filter((x) => {return (x != null)}) //flatten result
}

3

सममित और रैखिक जटिलता । ES6 की आवश्यकता है।

function arrDiff(arr1, arr2) {
    var arrays = [arr1, arr2].sort((a, b) => a.length - b.length);
    var smallSet = new Set(arrays[0]);

    return arrays[1].filter(x => !smallSet.has(x));
}

3

अभी तक एक और जवाब है, लेकिन ऐसा लगता है कि किसी ने भी jsperf का उल्लेख नहीं किया है, जहां वे कई एल्गोरिदम और प्रौद्योगिकी समर्थन की तुलना करते हैं: https://jsperf.com/array-difference-javascript का उपयोग करके लगता है कि फ़िल्टर का सबसे अच्छा परिणाम मिलता है। धन्यवाद


2

सिर्फ सोच ... एक चुनौती के लिए ;-) क्या यह काम करेगा ... (स्ट्रिंग्स, संख्याओं, आदि के मूल सरणियों के लिए) कोई शून्य सरणियाँ नहीं

function diffArrays(arr1, arr2, returnUnion){
  var ret = [];
  var test = {};
  var bigArray, smallArray, key;
  if(arr1.length >= arr2.length){
    bigArray = arr1;
    smallArray = arr2;
  } else {
    bigArray = arr2;
    smallArray = arr1;
  }
  for(var i=0;i<bigArray.length;i++){
    key = bigArray[i];
    test[key] = true;
  }
  if(!returnUnion){
    //diffing
    for(var i=0;i<smallArray.length;i++){
      key = smallArray[i];
      if(!test[key]){
        test[key] = null;
      }
    }
  } else {
    //union
    for(var i=0;i<smallArray.length;i++){
      key = smallArray[i];
      if(!test[key]){
        test[key] = true;
      }
    }
  }
  for(var i in test){
    ret.push(i);
  }
  return ret;
}

array1 = "test1", "test2","test3", "test4", "test7"
array2 = "test1", "test2","test3","test4", "test5", "test6"
diffArray = diffArrays(array1, array2);
//returns ["test5","test6","test7"]

diffArray = diffArrays(array1, array2, true);
//returns ["test1", "test2","test3","test4", "test5", "test6","test7"]

ध्यान दें कि छँटाई संभवतः ऊपर उल्लिखित नहीं होगी ... लेकिन यदि वांछित हो, तो इसे सॉर्ट करने के लिए सरणी पर .sort () कॉल करें।


2

मैं एक समान फ़ंक्शन चाहता था जो एक पुराने सरणी और एक नए सरणी में ले गया और मुझे अतिरिक्त वस्तुओं का एक सरणी और हटाए गए आइटमों का एक सरणी दिया, और मैं चाहता था कि यह कुशल हो (इसलिए नहीं। कोई नहीं!)।

: तुम मेरी प्रस्तावित समाधान यहाँ के साथ खेल सकते http://jsbin.com/osewu3/12

क्या कोई भी उस एल्गोरिथ्म में कोई समस्या / सुधार देख सकता है? धन्यवाद!

कोड सूचीकरण:

function diff(o, n) {
  // deal with empty lists
  if (o == undefined) o = [];
  if (n == undefined) n = [];

  // sort both arrays (or this won't work)
  o.sort(); n.sort();

  // don't compare if either list is empty
  if (o.length == 0 || n.length == 0) return {added: n, removed: o};

  // declare temporary variables
  var op = 0; var np = 0;
  var a = []; var r = [];

  // compare arrays and add to add or remove lists
  while (op < o.length && np < n.length) {
      if (o[op] < n[np]) {
          // push to diff?
          r.push(o[op]);
          op++;
      }
      else if (o[op] > n[np]) {
          // push to diff?
          a.push(n[np]);
          np++;
      }
      else {
          op++;np++;
      }
  }

  // add remaining items
  if( np < n.length )
    a = a.concat(n.slice(np, n.length));
  if( op < o.length )
    r = r.concat(o.slice(op, o.length));

  return {added: a, removed: r}; 
}

2

मैं एक सरल उत्तर की तलाश में था जिसमें विभिन्न पुस्तकालयों का उपयोग शामिल नहीं था, और मैं अपने साथ आया था कि मुझे नहीं लगता कि यहां उल्लेख किया गया है। मुझे नहीं पता कि यह कितना कुशल है या कुछ भी लेकिन यह काम करता है;

    function find_diff(arr1, arr2) {
      diff = [];
      joined = arr1.concat(arr2);
      for( i = 0; i <= joined.length; i++ ) {
        current = joined[i];
        if( joined.indexOf(current) == joined.lastIndexOf(current) ) {
          diff.push(current);
        }
      }
      return diff;
    }

मेरे कोड के लिए मुझे डुप्लिकेट के रूप में अच्छी तरह से बाहर निकालने की आवश्यकता है, लेकिन मुझे लगता है कि हमेशा पसंद नहीं किया जाता है।

मुझे लगता है कि मुख्य नकारात्मक पक्ष यह संभावित रूप से कई विकल्पों की तुलना कर रहा है जो पहले ही खारिज कर दिए गए हैं।


2

सबसे अच्छा जवाब के लिए थोड़ा तय

function arr_diff(a1, a2)
{
  var a=[], diff=[];
  for(var i=0;i<a1.length;i++)
    a[a1[i]]=a1[i];
  for(var i=0;i<a2.length;i++)
    if(a[a2[i]]) delete a[a2[i]];
    else a[a2[i]]=a2[i];
  for(var k in a)
   diff.push(a[k]);
  return diff;
}

यह वर्तमान प्रकार के तत्व को ध्यान में रखेगा। b / c जब हम एक [a1 [i] बनाते हैं, तो यह एक मान को उसके ऑरलिनल वैल्यू से स्ट्रिंग में परिवर्तित कर देता है, इसलिए हमने एक और वैल्यू खो दी है।


यह अभी भी वस्तुओं की एक सरणी के लिए विफल रहता है। var a = [{a: 1}], b = [{b: 2}] arr_diff (a, b) == []।
एरिका
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.