2009-02-06 9 views
46

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

return myList.Distinct((x, y) => x.Url == y.Url); 

मैं नहीं कर सकता वहाँ Linq में कोई विस्तार विधि है कि यह कर देगा नहीं है - केवल एक ही है कि एक IEqualityComparer लेता है:

मुझे क्या करना चाहते हैं कुछ इस तरह है।

मैं इस के साथ उसके चारों ओर हैक कर सकते हैं:

return myList.GroupBy(x => x.Url).Select(g => g.First()); 

लेकिन वह गंदा लगता है। यह भी वही काम नहीं करता है - मैं इसे केवल यहां उपयोग कर सकता हूं क्योंकि मेरे पास एक ही कुंजी है।

मैं भी अपने ही जोड़ सकते हैं:

public static IEnumerable<T> Distinct<T>( 
    this IEnumerable<T> input, Func<T,T,bool> compare) 
{ 
    //write my own here 
} 

लेकिन वह नहीं बल्कि कुछ है कि पहली जगह में होना चाहिए लेखन की तरह प्रतीत होता है।

कोई भी जानता है कि यह विधि क्यों नहीं है?

क्या मुझे कुछ याद आ रही है?

उत्तर

50

यह निश्चित रूप से परेशान है। यह मेरी "मोरलाइनक" परियोजना का हिस्सा भी है, जिसे मुझे किसी बिंदु पर कुछ ध्यान देना होगा :) ऐसे कई अन्य ऑपरेशन हैं जो प्रक्षेपण पर कार्य करते समय समझ में आते हैं, लेकिन मूल - मैक्सबी और मिनीबी वसंत को ध्यान में रखते हुए।

तुम कहते हो, यह लिखने के लिए आसान है - हालांकि मैं नाम "DistinctBy" मैच के लिए पसंद करते हैं OrderBy आदि यहाँ मेरी कार्यान्वयन अगर आप रुचि रखते हैं:

public static IEnumerable<TSource> DistinctBy<TSource, TKey> 
     (this IEnumerable<TSource> source, 
     Func<TSource, TKey> keySelector) 
    { 
     return source.DistinctBy(keySelector, 
           EqualityComparer<TKey>.Default); 
    } 

    public static IEnumerable<TSource> DistinctBy<TSource, TKey> 
     (this IEnumerable<TSource> source, 
     Func<TSource, TKey> keySelector, 
     IEqualityComparer<TKey> comparer) 
    { 
     if (source == null) 
     { 
      throw new ArgumentNullException("source"); 
     } 
     if (keySelector == null) 
     { 
      throw new ArgumentNullException("keySelector"); 
     } 
     if (comparer == null) 
     { 
      throw new ArgumentNullException("comparer"); 
     } 
     return DistinctByImpl(source, keySelector, comparer); 
    } 

    private static IEnumerable<TSource> DistinctByImpl<TSource, TKey> 
     (IEnumerable<TSource> source, 
     Func<TSource, TKey> keySelector, 
     IEqualityComparer<TKey> comparer) 
    { 
     HashSet<TKey> knownKeys = new HashSet<TKey>(comparer); 
     foreach (TSource element in source) 
     { 
      if (knownKeys.Add(keySelector(element))) 
      { 
       yield return element; 
      } 
     } 
    } 
+0

त्वरित उत्तर के लिए धन्यवाद - मैं इसका उपयोग कर सकता हूं! कोई विचार क्यों उन्होंने इन सभी को छोड़ दिया ... द्वारा (भविष्यवाणी) विधियों? – Keith

+0

वास्तव में नहीं, मुझे डर है। जब मैं सुविधाओं का एक महत्वपूर्ण सेट प्राप्त करता हूं तो मैं मोरलिंक प्रोजेक्ट के बारे में ब्लॉग करूंगा ... मूल रूप से यह एक ओपन सोर्स प्रोजेक्ट होगा जिसमें LINQ से ऑब्जेक्ट्स के एक्सटेंशन होंगे, और शायद पुश LINQ भी होगा। –

+7

अगर मुझे लगता है, तो मैं IQueryable विकल्पों के साथ समानता के लिए अनुमान लगाऊंगा, और टीएसक्यूएल में यथार्थवादी (बीमार होने के बिना) क्या है। तो DISTINCT (table.column) ठीक है, लेकिन आपको एक आसान कुंजी और DistinctBy के लिए कुछ और जटिल TSQL की आवश्यकता होगी ... –

31

लेकिन वह गंदा लगता है।

यह गन्दा नहीं है, यह सही है।

  • यदि आप Distinct फर्स्टनाम द्वारा प्रोग्रामर चाहते हैं और चार डेविड हैं, तो आप कौन सी चाहते हैं?
  • यदि आप Group प्रोग्रामर फर्स्टनाम द्वारा और First एक लेते हैं, तो यह स्पष्ट है कि आप चार डेविड के मामले में क्या करना चाहते हैं।

मैं केवल इसका उपयोग कर सकता हूं क्योंकि मेरे पास एक ही कुंजी है।

आप एक ही पैटर्न के साथ एक से अधिक कुंजी "अलग" कर सकते हैं:

return myList 
    .GroupBy(x => new { x.Url, x.Age }) 
    .Select(g => g.First()); 
+0

मैंने इस तरह के एनन प्रकारों का उपयोग करने के बारे में सोचा नहीं था - यह एक अच्छा विचार है (+1) – Keith

+0

अच्छा, छोटा, सरल, साफ नहीं: डी +1 – Cerbrus

+0

प्रत्येक व्यक्ति ने DistinctBy() के अपने कार्यान्वयन के साथ उत्तर दिया है, लेकिन यह है केवल एक जो वास्तविक प्रश्न को संबोधित करता है क्यों LINQ में कोई DistinctBy() नहीं है। धन्यवाद! – josh2112

3

जॉन, अपने समाधान बहुत अच्छा है। यद्यपि एक मामूली परिवर्तन। मुझे नहीं लगता कि हमें वहां समानता कॉम्पैयर की आवश्यकता है।यहाँ मेरी समाधान (प्रारंभिक बिंदु बिल्कुल था जॉन स्कीट के समाधान)

public static IEnumerable<T> DistinctBy<T, TKey>(this IEnumerable<T> source, Func<T, TKey> keySelector) 
    { 
     //TODO All arg checks 
     HashSet<TKey> keys = new HashSet<TKey>(); 
     foreach (T item in source) 
     { 
      TKey key = keySelector(item); 
      if (!keys.Contains(key)) 
      { 
       keys.Add(key); 
       yield return item; 
      } 
     } 
    } 
+2

मुझे यकीन नहीं है कि यह जॉन के समाधान से बेहतर क्यों होगा। 'नया हैशसेट ()' 'समानता कॉम्पैयर का उपयोग करेगा। डीफॉल्ट 'वैसे भी और इसे अपने तरीके से करने से आप इसे ओवरराइड करने की क्षमता खो देते हैं (उदाहरण के लिए यदि' टीकेई 'स्ट्रिंग है और आप केस असंवेदनशीलता चाहते हैं)। जब भी आप 'हैशसेट। सामग्री' का उपयोग करते हैं और फिर 'हैशसेट। जोड़ें' - दो ऑपरेशन का उपयोग करते हैं, तो जॉन 'हैशसेट। जोड़ें' विधि का उपयोग करता है। माना जाता है कि आपको अंतर देखने के लिए एक विशाल सेट की आवश्यकता होगी, लेकिन इसे धीमा क्यों करें? – Keith

0

का उपयोग करना @DavidB के answer एक विधेय पारित होने के लिए अनुमति देने के लिए, मैं एक छोटे से DistinctBy विस्तार विधि लिखा है, यह है:

/// <summary> 
/// Distinct method that accepts a perdicate 
/// </summary> 
/// <typeparam name="TSource">The type of the t source.</typeparam> 
/// <typeparam name="TKey">The type of the t key.</typeparam> 
/// <param name="source">The source.</param> 
/// <param name="predicate">The predicate.</param> 
/// <returns>IEnumerable&lt;TSource&gt;.</returns> 
/// <exception cref="System.ArgumentNullException">source</exception> 
public static IEnumerable<TSource> DistinctBy<TSource, TKey> 
    (this IEnumerable<TSource> source, 
    Func<TSource, TKey> predicate) 
{ 
    if (source == null) 
     throw new ArgumentNullException("source"); 

    return source 
     .GroupBy(predicate) 
     .Select(x => x.First()); 
} 

var distinct = myList.DistinctBy(x => x.Id); 

या समूह में अनेक प्रॉपर्टी द्वारा:

अब आप एक विधेय समूह के द्वारा सूची पारित कर सकते हैं

var distinct = myList.DistinctBy(x => new { x.Id, x.Title }); 
संबंधित मुद्दे

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