दो सूचियों के बीच अंतर


118

मैं CustomsObjects के साथ दो सामान्य सूची भरी है।

मुझे उन दो सूचियों के बीच अंतर को पुनः प्राप्त करने की आवश्यकता है (आइटम जो दूसरे में पहले आइटम के बिना हैं) एक तीसरे एक में।

मैं सोच रहा था कि .Except()यह एक अच्छा विचार है, लेकिन मैं यह नहीं देखता कि इसका उपयोग कैसे किया जाए .. मदद!

c# 

जवाबों:


237

उपयोग करना Exceptबिल्कुल सही तरीका है। यदि आपका प्रकार ओवरराइड करता है Equalsऔर GetHashCode, या आप केवल संदर्भ प्रकार समानता में रुचि रखते हैं (अर्थात दो संदर्भ केवल "बराबर" हैं यदि वे सटीक समान ऑब्जेक्ट को संदर्भित करते हैं), तो आप बस उपयोग कर सकते हैं:

var list3 = list1.Except(list2).ToList();

यदि आपको समानता के एक कस्टम विचार को व्यक्त करने की आवश्यकता है, जैसे आईडी द्वारा, तो आपको लागू करने की आवश्यकता होगी IEqualityComparer<T>। उदाहरण के लिए:

public class IdComparer : IEqualityComparer<CustomObject>
{
    public int GetHashCode(CustomObject co)
    {
        if (co == null)
        {
            return 0;
        }
        return co.Id.GetHashCode();
    }

    public bool Equals(CustomObject x1, CustomObject x2)
    {
        if (object.ReferenceEquals(x1, x2))
        {
            return true;
        }
        if (object.ReferenceEquals(x1, null) ||
            object.ReferenceEquals(x2, null))
        {
            return false;
        }
        return x1.Id == x2.Id;
    }
}

फिर उपयोग करें:

var list3 = list1.Except(list2, new IdComparer()).ToList();

ध्यान दें कि यह किसी भी डुप्लिकेट तत्वों को हटा देगा। यदि आपको डुप्लिकेट को संरक्षित करने की आवश्यकता है, तो संभवतः एक सेट बनाना list2और कुछ का उपयोग करना सबसे आसान होगा :

var list3 = list1.Where(x => !set2.Contains(x)).ToList();

18
बस एक अलग रूप में के रूप में, मैं जोड़ना होगा कि Exceptएक है सेट आपरेशन, फिर परिणामी सूची अलग-अलग मान, जैसे होगा {'A','A','B','C'}.Except({'B','C'}) रिटर्न{'A'}
digEmAll

4
मेरे पास यह है: {'ए', 'ए', 'बी', 'सी'}। सिवाय (('बी', 'सी')) रिटर्न {'ए'} जो काम करता है ... हालांकि {'बी' , 'सी'} (सिवाय इसके ({'ए', 'बी', 'सी')) वापस नहीं आता {'ए'}
मिस्टरिस्टर

2
दो सेटों के सेट अंतर को पहले सेट के सदस्यों के रूप में परिभाषित किया जाता है जो दूसरे सेट (एमएस को उद्धृत करते हुए) में प्रकट नहीं होते हैं। इसलिए, {B, C} .Except ({A, B, C}) को कुछ भी नहीं लौटाना चाहिए क्योंकि B और C दोनों दूसरे सेट में हैं। बग नहीं, फ़ंक्शन की गणितीय परिभाषा के साथ अधिक करने के लिए।
स्टीव हिबर्ट

तो @JonSkeet अगर मैं दो सूचियों की तुलना के आधार पर कहना चाहता हूं कि 2 गुण मैं इस तरह से लिख सकता हूं और उन वस्तुओं को प्राप्त कर सकता हूं जो समान नहीं हैं?
एहसान सज्जाद

1
@NetMage: ओपी ने कहा कि वे चाहते हैं कि "जो आइटम पहले वाले आइटम के बिना दूसरे एक में हों" - जो मेरे लिए एक अंतर की तरह लगता है। यदि पहली सूची में {5, 5, 5, 5, 1} है और दूसरी सूची में {5} है तो केवल 1 पहली सूची में है, लेकिन दूसरी नहीं है।
जॉन स्कीट

73

आप ऐसा कुछ कर सकते हैं:

var result = customlist.Where(p => !otherlist.Any(l => p.someproperty == l.someproperty));

इसने मुझे एक फॉरेस्ट लूप बचाया।
alice7

12
उन "l.someproperty" में से एक "p.someproperty" नहीं होना चाहिए?
मानोस डिल्वेरेकिस

6
इसे customlist के साथ सरलीकृत किया जा सकता है। कहीं भी (p => otherlist.Any (l => p.someproperty! = L.someproperty));
धानुका Dhan।

@ धनुका777 गलत है। Anyएक होना चाहिए Allअगर आपको लगता है कि जैसे कि यह करना चाहते हैं। ऐसा इसलिए है क्योंकि दूसरी सूची में पहली सूची से आइटम हो सकता है, लेकिन अगर यह पहली जांच नहीं है, तो यह तुरंत एक सच हो जाएगा p.someproperty != l.someproperty। यह आइटम वापस लौटाए जा रहे हैं जो दोनों सूचियों में मौजूद हैं। 6 लोगों पर शर्म आती है जिन्होंने इसे उकसाया।
मर्फ़ब्रोब 2

26

मुझे ज़ोर देना ज़रूरी लगता है - सिवाय सिवाय विधि के उपयोग के आप उन वस्तुओं को वापस कर देंगे जो पहली बार में वस्तुओं के बिना दूसरे एक में हैं। यह उन तत्वों को दूसरे में वापस नहीं करता है जो पहले दिखाई नहीं देते हैं।

var list1 = new List<int> { 1, 2, 3, 4, 5};
var list2 = new List<int> { 3, 4, 5, 6, 7 };

var list3 = list1.Except(list2).ToList(); //list3 contains only 1, 2

लेकिन अगर आप दो सूचियों के बीच वास्तविक अंतर चाहते हैं:

आइटम जो पहले एक में आइटम के बिना दूसरे में हैं और आइटम जो दूसरे में आइटम के बिना दूसरे में हैं।

आपको दो बार छोड़कर उपयोग करने की आवश्यकता है:

var list1 = new List<int> { 1, 2, 3, 4, 5};
var list2 = new List<int> { 3, 4, 5, 6, 7 };

var list3 = list1.Except(list2); //list3 contains only 1, 2
var list4 = list2.Except(list1); //list4 contains only 6, 7
var resultList = list3.Concat(list4).ToList(); //resultList contains 1, 2, 6, 7

या आप HashSet की SymmetricExceptWith विधि का उपयोग कर सकते हैं । लेकिन यह सेट को बदल देता है जिस पर कहा जाता है:

var list1 = new List<int> { 1, 2, 3, 4, 5};
var list2 = new List<int> { 3, 4, 5, 6, 7 };

var list1Set = list1.ToHashSet(); //.net framework 4.7.2 and .net core 2.0 and above otherwise new HashSet(list1)
list1Set.SymmetricExceptWith(list2);
var resultList = list1Set.ToList(); //resultList contains 1, 2, 6, 7

वह मददगार है। बस जागरूक रहें ओपी ने स्पष्ट किया कि वे पूर्ण अंतर नहीं चाहते थे: "मुझे उन दो सूचियों के बीच अंतर को पुनः प्राप्त करने की आवश्यकता है ( जो आइटम पहले दूसरे में आइटम के बिना हैं )"।
रासना

10
var third = first.Except(second);

(आप ToList()बाद में भी कॉल कर सकते हैं Except(), यदि आपको आलसी संग्रह संदर्भित करना पसंद नहीं है।)

Except()विधि, डिफ़ॉल्ट comparer का उपयोग कर मूल्यों तुलना करता है, तो मान तुलना की जा रही आधार डेटा प्रकार के होते हैं, जैसे int, string, decimalआदि

अन्यथा तुलना वस्तु पते से की जाएगी, जो कि शायद आप नहीं चाहते हैं ... उस स्थिति में, अपने कस्टम ऑब्जेक्ट्स को लागू करें IComparable(या एक कस्टम लागू करें IEqualityComparerऔर इसे Except()विधि को पास करें )।


3
var list3 = list1.Where(x => !list2.Any(z => z.Id == x.Id)).ToList();

नोट: list3उन वस्तुओं या वस्तुओं को शामिल किया जाएगा जो दोनों सूचियों में नहीं हैं। नोट: इसकी ToList()नहींtoList()


1

चूंकि एक्स्टेंशन एक्सटेंशन विधि दो IEumerables पर संचालित होती है, यह मुझे लगता है कि यह एक ओ (एन ^ 2) ऑपरेशन होगा। यदि प्रदर्शन एक समस्या है (यदि आपकी सूचियाँ बड़ी हैं), तो मैं सूची 1 से एक हैशसेट बनाने का सुझाव दूंगा और हैशसेट के अतिरिक्त तरीके का उपयोग करूंगा।


9
Enumerable.Exceptआंतरिक रूप से HashSetया कुछ इसी तरह का उपयोग करता है । यह निश्चित रूप से भोले हे (n ^ 2) एल्गोरिथ्म का उपयोग नहीं करता है।
जिम मिसथेल

@Jim Mischel: आप सही हैं, Enumerable.Except एक आंतरिक सेट डेटा संरचना का उपयोग करता है और सेट में दोनों IEnumerables से आइटम जोड़ता है। काश दस्तावेजीकरण उस बारे में कुछ कहता।
फोसन

1

यहाँ मेरा समाधान है:

    List<String> list1 = new List<String>();

    List<String> list2 = new List<String>();

    List<String> exceptValue = new List<String>();

foreach(String L1 in List1) 
{
    if(!List2.Contains(L1)
    {
         exceptValue.Add(L1);
    }
}
foreach(String L2 in List2) 
{
    if(!List1.Contains(L2)
    {
         exceptValue.Add(L2);
    }
}

-1

थोड़ा देर से लेकिन यहाँ मेरे लिए काम कर रहा है समाधान

 var myBaseProperty = (typeof(BaseClass)).GetProperties();//get base code properties
                    var allProperty = entity.GetProperties()[0].DeclaringType.GetProperties();//get derived class property plus base code as it is derived from it
                    var declaredClassProperties = allProperty.Where(x => !myBaseProperty.Any(l => l.Name == x.Name)).ToList();//get the difference

उपर्युक्त कोड में मुझे अपने आधार वर्ग और व्युत्पन्न वर्ग सूची के बीच गुण अंतर मिल रहा है


-1
var resultList = checklist.Where(p => myList.All(l => p.value != l.value)).ToList();

नोट: परिणाम सूची वह आइटम है जो चेकलिस्ट में मौजूद है, लेकिन myList में नहीं है
Teezy7

-2
List<ObjectC> _list_DF_BW_ANB = new List<ObjectC>();    
List<ObjectA> _listA = new List<ObjectA>();
List<ObjectB> _listB = new List<ObjectB>();

foreach (var itemB in _listB )
{     
    var flat = 0;
    foreach(var itemA in _listA )
    {
        if(itemA.ProductId==itemB.ProductId)
        {
            flat = 1;
            break;
        }
    }
    if (flat == 0)
    {
        _list_DF_BW_ANB.Add(itemB);
    }
}

स्वीकृत उत्तर के 6 साल बाद और मूल्य का कुछ भी नया नहीं जोड़ा जाता है
मिच गेहूं

-3

यदि आपकी दोनों सूची IEnumerable इंटरफ़ेस को लागू करती हैं, तो आप LINQ का उपयोग करके इसे प्राप्त कर सकते हैं।

list3 = list1.where(i => !list2.contains(i));

6
और यदि आपकी सूचियों में प्रत्येक में एक लाख आइटम हैं, तो आप लंबे समय तक प्रतीक्षा करने वाले हैं। IEnumerable.Exceptइसके बजाय उपयोग करें ।
जिम मेंथेल

3
हां। मेरे पास लगभग 450 आइटम हैं और मैं अभी भी इंतजार कर रहा हूं। इसके इस्तेमाल से सावधान रहें।
मार्नी KG7SIO

-3
        List<int> list1 = new List<int>();
        List<int> list2 = new List<int>();
        List<int> listDifference = new List<int>();

        foreach (var item1 in list1)
        {
            foreach (var item2 in list2)
            {
                if (item1 != item2)
                    listDifference.Add(item1);
            }
        }
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.