2010-07-18 23 views
65

निर्धारित करने के लिए अगर एक IEnumerable जब दोनों संग्रह में प्रत्येक तत्व का एक क्षेत्र/संपत्ति की तुलना एक और IEnumerable के सभी तत्व शामिल हैं सबसे तेज़ तरीका क्या है के सभी तत्व शामिल हैं?चेक एक अगर IEnumerable एक और IEnumerable


public class Item 
{ 
    public string Value; 

    public Item(string value) 
    { 
     Value = value; 
    } 
} 

//example usage 

Item[] List1 = {new Item("1"),new Item("a")}; 
Item[] List2 = {new Item("a"),new Item("b"),new Item("c"),new Item("1")}; 

bool Contains(IEnumerable<Item> list1, IEnumerable<Item>, list2) 
{ 
    var list1Values = list1.Select(item => item.Value); 
    var list2Values = list2.Select(item => item.Value); 

    return //are ALL of list1Values in list2Values? 
} 

Contains(List1,List2) // should return true 
Contains(List2,List1) // should return false 
+1

किस तरह दौर अपनी सूची रहे हैं? क्या आप यह जांचना चाहते हैं कि सूची 1 में सभी आइटम सूची 2 में हैं या सूची 2 में सभी आइटम सूची 1 में हैं या नहीं? –

उत्तर

94

नहीं "तेज़ तरीका" जब तक आप पर नज़र रखने और कुछ राज्य निर्धारित करता है कि एक संग्रह में सभी मान एक और में निहित हैं कि क्या बनाए रखने के यह करने के लिए नहीं है। यदि आपके पास काम करने के लिए केवल IEnumerable<T> है, तो मैं Intersect का उपयोग करूंगा।

var allOfList1IsInList2 = list1.Intersect(list2).Count() == list1.Count(); 

इस के प्रदर्शन, बहुत ही उचित होना चाहिए, क्योंकि Intersect() सिर्फ एक बार प्रत्येक सूची से अधिक की गणना करेगा। इसके अलावा, Count() को दूसरी कॉल इष्टतम हो जाएगा अगर अंतर्निहित प्रकार एक ICollection<T> के बजाय सिर्फ एक IEnumerable<T> है।

+0

मैंने कुछ परीक्षण किए और यह तरीका दूसरों की तुलना में तेज़ी से चल रहा है। पारितोषिक के लिए धन्यवाद। –

+0

मुझे लगता है कि आपका मतलब है 'var allOfList2IsInList1 = list1.Intersect (list2)। गणना() == list2.Count(); ' – dan

+2

@fsmmu: नहीं, मैंने नहीं किया। पहली कॉल में पता चलता है कि सूचियों 1 और 2 के चौराहे में कितनी वस्तुएं हैं। दूसरी कॉल में पता चलता है कि सूची में कितनी वस्तुएं हैं 1. यदि वे संख्याएं समान हैं, तो ओपी के अनुसार सभी सूची 1 सूची 2 में है सवाल। –

2

Linq ऑपरेटर SequenceEqual भी काम करेगा (लेकिन गणनीय के उसी क्रम में किया जा रहा है आइटम के प्रति संवेदनशील है)

return list1Uris.SequenceEqual(list2Uris); 
18

सी # 3.5+

अगर निर्धारित करने के लिए Enumerable.All<TSource> का उपयोग करना सभी List2 आइटम List1 में निहित हैं:

bool hasAll = list2Uris.All(itm2 => list1Uris.Contains(itm2)); 
,210

यह भी काम करेगा जब List1 भी सभी की तुलना में अधिक List2 के आइटम शामिल हैं।

+8

'सभी()' कॉल के भीतर 'कंटेनर()' कॉल के प्रदर्शन प्रभावों पर बहुत अधिक है। –

+0

इसके अलावा आप इसे समूह विधि में स्थानांतरित कर सकते हैं: bool hasAll = list2Uris.All (list1Uris.Contains); – jimpanzer

+0

INumerable प्रकारों का मामला यह समाधान एन * एम प्रदर्शन प्रदान करेगा। –

31

तुम भी इस्तेमाल कर सकते हैं सिवाय सभी मूल्यों है कि दूसरी सूची में मौजूद पहली सूची से हटाने, और फिर जाँच लें कि सभी मूल्यों निकाल दी गई है:

var allOfList1IsInList2 = !list1.Except(list2).Any(); 

इस विधि दो की जरूरत नहीं का लाभ था गणना करने के लिए कॉल()।

+0

यह सूची 1 में क्या है, यह जानने के लिए भी अच्छा है लेकिन सूची 2 में नहीं; – Homer

+5

यह उन परिस्थितियों में काम करता है जहां सूची 1 में डुप्लिकेट मान हैं। स्वीकृत उत्तर नहीं है। – dbc

4

समाधान चिह्नित जवाब के रूप में पुनरावृत्ति के मामले में विफल हो जाएगा। यदि आपके IENumerable में केवल विशिष्ट मान हैं तो यह गुजर जाएगा।

 int aCount = a.Distinct().Count(); 
     int bCount = b.Distinct().Count(); 

     return aCount == bCount && 
       a.Intersect(b).Count() == aCount; 
3

केंट के जवाब ठीक है और छोटा है, लेकिन समाधान प्रदान करता है कि वह हमेशा पूरे पहला संग्रह से अधिक यात्रा की आवश्यकता है:

नीचे जवाब repetitions के साथ 2 सूचियों के लिए है। यहां स्रोत कोड है:

public static IEnumerable<TSource> Intersect<TSource>(this IEnumerable<TSource> first, IEnumerable<TSource> second, IEqualityComparer<TSource> comparer) 
{ 
    if (first == null) 
     throw Error.ArgumentNull("first"); 
    if (second == null) 
     throw Error.ArgumentNull("second"); 
    return Enumerable.IntersectIterator<TSource>(first, second, comparer); 
} 

private static IEnumerable<TSource> IntersectIterator<TSource>(IEnumerable<TSource> first, IEnumerable<TSource> second, IEqualityComparer<TSource> comparer) 
{ 
    Set<TSource> set = new Set<TSource>(comparer); 
    foreach (TSource source in second) 
     set.Add(source); 
    foreach (TSource source in first) 
    { 
     if (set.Remove(source)) 
      yield return source; 
    } 
} 

यह हमेशा आवश्यक नहीं है।

public static bool Contains<T>(this IEnumerable<T> source, IEnumerable<T> subset, IEqualityComparer<T> comparer) 
{ 
    var hashSet = new HashSet<T>(subset, comparer); 
    if (hashSet.Count == 0) 
    { 
     return true; 
    } 

    foreach (var item in source) 
    { 
     hashSet.Remove(item); 
     if (hashSet.Count == 0) 
     { 
      break; 
     } 
    } 

    return hashSet.Count == 0; 
} 

असल में, आप ISet<T> (HashSet<T>) का उपयोग कर के बारे में सोचना चाहिए: तो, यहाँ मेरी समाधान है। इसमें सभी आवश्यक सेट विधियां हैं। आपके मामले में IsSubsetOf

-1

आप तुलना दो सूची

//Method to compare two list 
    private bool Contains(IEnumerable<Item> list1, IEnumerable<Item> list2) 
    { 
     bool result; 

     //Get the value 
     var list1WithValue = list1.Select(s => s.Value).ToList(); 
     var list2WithValue = list2.Select(s => s.Value).ToList(); 

     result = !list1WithValue.Except(list2WithValue).Any(); 

     return result; 
    } 
+0

बहुत अधिक वही उत्तर 3 साल पहले दिया गया था: http://stackoverflow.com/a/16967827/5282087 – Dragomok

0

आप सरणी के बजाय HashSet का उपयोग करना चाहिए करने के लिए इस विधि का उपयोग कर सकते हैं।

उदाहरण:

List1.SetEquals(List2); //returns true if the collections contains exactly same elements no matter the order they appear in the collection 

Reference

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

कृपया मुझे पता है कि अगर आप के लिए काम करता है

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