2011-09-15 7 views
8

क्या सबसे कारगर तरीका एक विधि है कि n सूचियों की तुलना और सभी मूल्यों है कि सभी सूचियों में दिखाई नहीं देते वापस आ जाएगी लिखने के लिए है, इसलिए किLinq मूल्यों को प्राप्त एकाधिक सूचियों के बीच साझा नहीं

var lists = new List<List<int>> { 
            new List<int> { 1, 2, 3, 4 }, 
            new List<int> { 2, 3, 4, 5, 8 }, 
            new List<int> { 2, 3, 4, 5, 9, 9 }, 
            new List<int> { 2, 3, 3, 4, 9, 10 } 
           }; 


public IEnumerable<T> GetNonShared(this IEnumerable<IEnumerable<T>> lists) 
{ 
    //...fast algorithm here 
} 

ताकि

सूचियां। GetNonShared();

रिटर्न 1, 5, 8, 9, 10

मैं

public IEnumerable<T> GetNonShared(this IEnumerable<IEnumerable<T>> lists) 
{ 
    return list.SelectMany(item => item) 
      .Except(lists.Aggregate((a, b) => a.Intersect(b)); 
} 

था लेकिन मुझे यकीन है कि अगर कुशल था नहीं था। आदेश कोई फर्क नहीं पड़ता। धन्यवाद!

+1

के लिए आप यकीन है कि अगर यह "कुशल" नहीं कर रहे हैं? यह मुद्दा नहीं है। मुद्दा यह है: अर्थशास्त्र सही हैं, और क्या यह आपकी प्रदर्शन आवश्यकताओं को पूरा करता है? आपके कार्यान्वयन के अर्थशास्त्र सही हैं। केवल आप ही जान सकते हैं कि यह आपकी प्रदर्शन आवश्यकताओं को पूरा करता है या नहीं। – jason

उत्तर

5
 public static IEnumerable<T> GetNonShared<T>(this IEnumerable<IEnumerable<T>> list) 
     { 
      return list.SelectMany(x => x.Distinct()).GroupBy(x => x).Where(g => g.Count() < list.Count()).Select(group => group.Key); 
     } 
+0

प्रदान की गई सूची ओपी में से एक में से 9 जोड़ें और यह विफल हो जाता है। –

+0

डिस्टिंट() – mironych

2

संपादित करें: मुझे लगता है मैं इस तरह इसके बारे में लगता है कि ...

आप सभी सूचियों का संघ चाहते हैं, शून्य से सभी सूचियों की चौराहे। डुप्लिकेट इनपुट प्राप्त करने के बावजूद Union के "सेट" ऑपरेशन को करने के लिए Except छोड़कर यह प्रभावी रूप से आपके मूल कार्य करता है। इस मामले में मैं संदिग्ध आप इस और अधिक कुशलता से कर सकता है सिर्फ दो HashSet रों के निर्माण और यथा-स्थान सब काम कर रही:

public IEnumerable<T> GetNonShared(this IEnumerable<IEnumerable<T>> lists) 
{   
    using (var iterator = lists.GetEnumerator()) 
    { 
     if (!iterator.MoveNext()) 
     { 
      return new T[0]; // Empty 
     } 

     HashSet<T> union = new HashSet<T>(iterator.Current.ToList()); 
     HashSet<T> intersection = new HashSet<T>(union); 
     while (iterator.MoveNext()) 
     { 
      // This avoids iterating over it twice; it may not be necessary, 
      // it depends on how you use it. 
      List<T> list = iterator.Current.Toist(); 
      union.UnionWith(list); 
      intersection = intersection.IntersectWith(list); 
     } 
     union.ExceptWith(intersection); 
     return union; 
    } 
} 

ध्यान दें कि यह अब के लिए उत्सुक है, नहीं टाल।

public IEnumerable<T> GetNonShared(this IEnumerable<IEnumerable<T>> lists) 
{ 
    return list.SelectMany(list => list) 
       .GroupBy(x => x) 
       .Where(group => group.Count() < lists.Count) 
       .Select(group => group.Key); 
} 

यदि यह एक सूची एक ही आइटम एक बार से अधिक शामिल करने के लिए के लिए संभव है, तुम वहाँ में एक विशिष्ट कॉल चाहते हैं:

public IEnumerable<T> GetNonShared(this IEnumerable<IEnumerable<T>> lists) 
{ 
    return list.SelectMany(list => list.Distinct()) 
       .GroupBy(x => x) 
       .Where(group => group.Count() < list.Count) 
       .Select(group => group.Key); 
} 


यहाँ एक वैकल्पिक विकल्प है

संपादित करें: अब मैंने इसे सही कर दिया है, मैं आपका मूल कोड समझता हूं ... और मुझे संदेह है कि मुझे कुछ बेहतर मिल सकता है ... सोच रहा है ...

+1

इसमें 5 और 9 शामिल नहीं हैं। वह केवल सभी सूचियों को छोड़कर मानों को सामान्य चाहता है। –

+0

@ ऑस्टिन: आह, गलत पढ़ना। हालांकि आसान फिक्स :) –

+0

वह सभी सूचियों को flattens, और फिर उन सभी वस्तुओं को हटा देता है जो सभी सूचियों में हैं (जो कुल ऑपरेशन द्वारा गणना की जाती है)। – jason

0

मुझे लगता है कि आपको एक मध्यवर्ती चरण बनाने की आवश्यकता है, जो सभी वस्तुओं को सभी सूचियों में ढूंढ रहा है। सेट लॉजिक के साथ यह करना आसान है - यह केवल प्रत्येक सूची में आइटम्स के सेट के साथ छेड़छाड़ की गई पहली सूची में आइटम्स का सेट है। मुझे नहीं लगता कि LINQ में चरण का काम करने योग्य है, हालांकि।

class Program 
{ 
    static void Main(string[] args) 
    { 
     IEnumerable<IEnumerable<int>> lists = new List<IEnumerable<int>> { 
           new List<int> { 1, 2, 3, 4 }, 
           new List<int> { 2, 3, 4, 5, 8 }, 
           new List<int> { 2, 3, 4, 5, 9, 9 }, 
           new List<int> { 2, 3, 3, 4, 9, 10 } 
          }; 

     Console.WriteLine(string.Join(", ", GetNonShared(lists) 
      .Distinct() 
      .OrderBy(x => x) 
      .Select(x => x.ToString()) 
      .ToArray())); 
     Console.ReadKey(); 
    } 

    public static HashSet<T> GetShared<T>(IEnumerable<IEnumerable<T>> lists) 
    { 
     HashSet<T> result = null; 
     foreach (IEnumerable<T> list in lists) 
     { 
      result = (result == null) 
         ? new HashSet<T>(list) 
         : new HashSet<T>(result.Intersect(list)); 
     } 
     return result; 
    } 

    public static IEnumerable<T> GetNonShared<T>(IEnumerable<IEnumerable<T>> lists) 
    { 
     HashSet<T> shared = GetShared(lists); 
     return lists.SelectMany(x => x).Where(x => !shared.Contains(x)); 
    } 
} 
0
public static IEnumerable<T> GetNonShared<T>(this IEnumerable<IEnumerable<T>> list) 
{ 
    var lstCnt=list.Count(); //get the total number if items in the list         
    return list.SelectMany (l => l.Distinct()) 
     .GroupBy (l => l) 
     .Select (l => new{n=l.Key, c=l.Count()}) 
     .Where (l => l.c<lstCnt) 
     .Select (l => l.n) 
     .OrderBy (l => l) //can be commented 
     ; 
} 

// HashSet और SymmetricExceptWith का उपयोग .net> = 4.5

+0

के साथ तय किया गया है जो आपके उत्तर के बारे में बताने के लिए और अधिक उपयोगी है। –

+1

यह मूल रूप से प्रत्येक अलग-अलग सूची से सभी अलग-अलग आइटमों को एक फ़्लैटेड आउट (selectMany) सूची में प्राप्त करता है, फिर प्रत्येक आइटम का समूह अपने मूल्य से कितनी बार प्राप्त करता है (l.c) यह (lnn) होता है (फ़्लैटेड सूची में)। यदि l.c (किसी भी आइटम के लिए) व्यक्तिगत सूची (lstCnt) की कुल संख्या से कम है तो हम यह सुनिश्चित करने के लिए कह सकते हैं कि आइटम कम से कम एक सूची में मौजूद नहीं था। – SKG

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