जांचें कि क्या एक IEnumerable में एक और IEnumerable के सभी तत्व शामिल हैं


102

यह निर्धारित करने का सबसे तेज़ तरीका क्या है कि दोनों संग्रह में प्रत्येक तत्व के क्षेत्र / संपत्ति की तुलना करते समय एक 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 में हैं?
मार्क बायर्स

जवाबों:


138

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

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

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


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

2
सूची में डुप्लिकेट होने पर यह काम नहीं करता है। उदाहरण के लिए ४४१ और ४१४ के चार वर्णों की तुलना करना ४१ देता है और इस प्रकार गिनती विफल हो जाती है।
जॉन

69

आप पहली सूची से निकालने के लिए छोड़कर भी उपयोग कर सकते हैं दूसरी सूची में मौजूद सभी मान, और फिर जांचें कि क्या सभी मान हटा दिए गए हैं:

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

इस विधि में काउंट () के लिए दो कॉल की आवश्यकता नहीं होने का लाभ था।


यह भी पता लगाने के लिए अच्छा है कि सूची 1 में क्या है, लेकिन सूची 2 में नहीं;
होमर

16
यह उन परिस्थितियों में काम करता है जहां list1 में मूल्यों का दोहराव होता है। स्वीकृत उत्तर नहीं है।
dbc

23

C # 3.5+

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

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

यह तब भी काम करेगा जब list1 में list2 के सभी आइटमों से भी अधिक होता है।


10
एक Contains()कॉल के भीतर प्रदर्शन के निहितार्थ पर आउच All()
कैंट बूगार्ट

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

मैं IEnumerable <T> प्रकार के मामले में यह समाधान n * m प्रदर्शन प्रदान करेगा।
बजे दिमित्री डॉकशिन

5
शॉर्टहैंड: bool hasAll = list2Uris.All(list1Uris.Contains);
इल्यूमिनेटर

3

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

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आपके मामले में।


2

Linq ऑपरेटर SequenceEqual भी काम करेगा (लेकिन एक ही क्रम में होने वाली असंख्य वस्तुओं के लिए संवेदनशील है)

return list1Uris.SequenceEqual(list2Uris);

2

उत्तर के रूप में चिह्नित समाधान दोहराव के मामले में विफल हो जाएगा। यदि आपके IEnumerable में केवल अलग मूल्य हैं तो यह पास होगा।

नीचे दिया गया उत्तर दोहराव के साथ 2 सूचियों के लिए है:

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

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

यह सभी डुप्लिकेट को हटाने और वास्तव में उनकी तुलना नहीं करने के बाद से एक अच्छा समाधान नहीं है।
जॉन

2

आपको ऐरे की जगह हैशसेट का इस्तेमाल करना चाहिए।

उदाहरण:

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

संदर्भ

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

कृपया मुझे बताएं कि क्या आपके लिए काम करता है


-2

आप दो सूची की तुलना करने के लिए इस विधि का उपयोग कर सकते हैं

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

बहुत ज्यादा एक ही जवाब 3 साल पहले दिया गया था: stackoverflow.com/a/16967827/5282087
Dragomok
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.