2008-12-02 19 views
116

इसकी जांच करने का है कि क्या उस सूची किसी अन्य का सबसेट है पर कोई विचार के एक सबसेट है कि क्या?एक सरणी एक और

विशेष रूप से, मैं

List<double> t1 = new List<double> { 1, 3, 5 }; 
List<double> t2 = new List<double> { 1, 5 }; 

कैसे जाँच करने के लिए है कि t2 t1 के एक सबसेट है, LINQ का उपयोग कर है?

+0

यदि सूचियों को क्रमबद्ध किया गया है (जैसा कि आपके उदाहरण में है), यह ओ (एन + एम) समय में संभव होना चाहिए। –

उत्तर

217
bool isSubset = !t2.Except(t1).Any(); 
+14

ब्रेवटी की सुंदरता! – JaredPar

+1

मैंने एक्सटेंशन विधि बनाई है http://geekswithblogs.net/mnf/archive/2011/05/13/issubsetof-list-extension.aspx –

+1

क्या आप थोड़ा सा समझा सकते हैं कि यह कैसे काम करता है? –

0

इस

static bool IsSubSet<A>(A[] set, A[] toCheck) { 
    return set.Length == (toCheck.Intersect(set)).Count(); 
} 

विचार यहाँ है कि इंटरसेक्ट केवल मूल्यों है कि दोनों सरणी में हैं वापस आ जाएगी की कोशिश करो। इस बिंदु पर यदि परिणामी सेट की लंबाई मूल सेट के समान होती है, तो "सेट" में सभी तत्व "चेक" में भी होते हैं और इसलिए "सेट" "टू चेक" का उप-समूह होता है

नोट: मेरा समाधान काम नहीं करता है, तो "सेट" डुप्लिकेट है। मैं इसे बदल नहीं रहा हूँ क्योंकि मैं अन्य लोगों के वोट चोरी करने के लिए नहीं करना चाहती।

संकेत: मैंने कैमरून के उत्तर के लिए मतदान किया।

+0

वाह, उत्कृष्ट समाधान। –

+3

यह काम करता है अगर वे वास्तव में सेट होते हैं, लेकिन यदि दूसरा "सेट" में बार-बार तत्व शामिल नहीं होते हैं क्योंकि यह वास्तव में एक सूची है। यह सुनिश्चित करने के लिए कि आपने अर्थशास्त्र सेट किया है, आप हैशसेट का उपयोग करना चाह सकते हैं। – tvanfosson

+0

यह मेरे सिर पर है। यह जानना अच्छा है कि मेरे पास सीखने के लिए बहुत कुछ है। ;) – Stefan

46

सेट के साथ काम करते समय सूची के बजाय हैशसेट का उपयोग करें। फिर आप आसानी से IsSubsetOf()

HashSet<double> t1 = new HashSet<double>{1,3,5}; 
HashSet<double> t2 = new HashSet<double>{1,5}; 

bool isSubset = t2.IsSubsetOf(t1); 

क्षमा करें कि यह LINQ का उपयोग नहीं करता है। :-(

आप सूचियों का उपयोग करने की आवश्यकता है, तो @ जारेड के समाधान चेतावनी कि आप किसी भी दोहराया तत्वों है कि मौजूद हटाने की आवश्यकता होगी के साथ काम करता

+2

बिल्कुल। आप एक सेट ऑपरेशन चाहते हैं, उनके लिए डिज़ाइन की गई कक्षा का उपयोग करें। कैमरून का समाधान रचनात्मक है, लेकिन हैशसेट के रूप में स्पष्ट/अभिव्यक्तिपूर्ण नहीं है। – technophile

+2

उम मैं असहमत हूं क्योंकि सवाल विशेष रूप से "LINQ का उपयोग" कहता है। – JaredPar

+0

आपके पास कोड की तीसरी पंक्ति में एक टाइपो है। –

4

@ एक विस्तार पद्धति के रूप में कैमरून के समाधान:।

public static bool IsSubsetOf<T>(this IEnumerable<T> a, IEnumerable<T> b) 
{ 
    return !a.Except(b).Any(); 
} 

उपयोग:

bool isSubset = t2.IsSubsetOf(t1); 

(यह समान है, लेकिन काफी के रूप में ही नहीं एक @ माइकल के ब्लॉग)

8

पर पोस्ट आप इकाई परीक्षण आप भी CollectionAssert.IsSubsetOf पद्धति का उपयोग कर सकते हैं:

ऊपर मामले में इसका मतलब यह होगा:

CollectionAssert.IsSubsetOf(t2, t1); 
1

यह यहां पोस्ट किए गए अन्य लोगों की तुलना में एक महत्वपूर्ण रूप से अधिक कुशल समाधान है, विशेष रूप से शीर्ष समाधान:

bool isSubset = t2.All(elem => t1.Contains(elem)); 

यदि आप टी 2 में एक तत्व नहीं पा सकते हैं जो टी 1 में नहीं है, तो आप जानते हैं कि टी 2 टी 1 का सबसेट नहीं है। इस विधि का लाभ यह है कि यह सभी इन-जगह किया जाता है, अतिरिक्त स्थान का आवंटन बिना, .Except या .Intersect का उपयोग कर समाधान के विपरीत है। इसके अलावा, इस समाधान, के रूप में यह एक भी तत्व यह है कि सबसेट हालत का उल्लंघन करता है जैसे ही तोड़ने में सक्षम है, जबकि अन्य खोज कर रहे हैं। नीचे समाधान है, जो केवल मामूली तेजी से ऊपर आशुलिपि समाधान की तुलना में मेरी परीक्षणों में है के इष्टतम लंबे रूप है।

bool isSubset = true; 
foreach (var element in t2) { 
    if (!t1.Contains(element)) { 
     isSubset = false; 
     break; 
    } 
} 

मैंने सभी समाधानों का कुछ प्राथमिक प्रदर्शन विश्लेषण किया, और परिणाम कठोर हैं। ये दो समाधान .xcept() और .tersect() समाधान से लगभग 100x तेज हैं, और कोई अतिरिक्त मेमोरी का उपयोग नहीं करते हैं।

+0

यह वही है जो '! T2.Except (t1) .अन्य()' कर रहा है। लिंक आगे काम कर रहा है। 'कोई भी() 'कम से कम एक तत्व होने पर' inumerable' पूछ रहा है। इस परिदृश्य में 't2.Except (t1)' केवल 't2' का पहला तत्व उत्सर्जित कर रहा है जो 't1' में नहीं है। यदि 't2' का पहला तत्व' t1' में नहीं है तो यह सबसे तेज़ हो जाता है, यदि 't2' के सभी तत्व' t1' में हैं तो यह सबसे लंबा चलता है। – abto

+0

किसी प्रकार के बेंचमार्क के साथ खेलते समय, मुझे पता चला, जब आप 't1 = {1,2,3, ... 99 99}' और 't2 = {9999,9998,99997 ... 9000}' लेते हैं, आपको निम्न माप मिलते हैं: '! t2.Except (t1) .एनी(): 1ms -> t2.All (e => t1.Contains (e)): 702ms'। और यह सीमा जितनी बड़ी होगी उतनी ही बदतर हो जाएगी। – abto

+0

यह गलत है। t2.Except (t1) एक सेट घटाव ऑपरेशन है, और t2 minus t1 के सभी शेष तत्व लौटाता है। यह एक नया नया संग्रह बनाता है, और ऐसा करने के लिए अतिरिक्त मेमोरी की आवश्यकता होती है। यह केवल टी 2 का पहला तत्व उत्सर्जित नहीं कर रहा है जो टी 1 में नहीं है, यह टी 2 के सभी तत्वों को उत्सर्जित कर रहा है जो टी 1 में नहीं हैं। टी 1 में नहीं सभी तत्वों के सेट को वापस करने के लिए, इसे पूरे सेट को पार करना होगा। उदाहरण के लिए, यदि टी 2 = {1,2,3,4,5,6,7,8} और टी 1 = {2,4,6,8}, तो t2.Except (t1) रिटर्न {1,3,5 , 7}। – user2325458

0

@ कैमरॉन और @ नेइल I के उत्तरों पर बिल्डिंग ने एक विस्तार विधि लिखा जो समान शब्दावली का उपयोग संख्यात्मक वर्ग के रूप में करता है।

/// <summary> 
/// Determines whether a sequence contains the specified elements by using the default equality comparer. 
/// </summary> 
/// <typeparam name="TSource">The type of the elements of source.</typeparam> 
/// <param name="source">A sequence in which to locate the values.</param> 
/// <param name="values">The values to locate in the sequence.</param> 
/// <returns>true if the source sequence contains elements that have the specified values; otherwise, false.</returns> 
public static bool ContainsAll<TSource>(this IEnumerable<TSource> source, IEnumerable<TSource> values) 
{ 
    return !values.Except(source).Any(); 
}