2010-12-14 8 views
9

हाल ही में, मैं एक तालिका से एक अलग श्रेणी (एक enum) का चयन करने के लिए LINQ में एक डिस्टिंट का उपयोग कर रहा था। यह ठीक काम कर रहा था।LINQ और ऑब्जेक्ट्स के साथ विशिष्ट का उपयोग

अब मुझे एक श्रेणी और देश (दोनों enums) वाले वर्ग पर इसे अलग करने की आवश्यकता है। विशिष्ट अब काम नहीं कर रहा है।

मैं क्या गलत कर रहा हूं?

उत्तर

13

मेरा मानना ​​है कि इस पोस्ट आपकी समस्या को बताते हैं: http://blog.jordanterrell.com/post/LINQ-Distinct()-does-not-work-as-expected.aspx

ऊपर के लिंक की सामग्री के कह रही है कि विशिष्ट() विधि निम्नलिखित कार्य करके बदला जा सकता है द्वारा अभिव्यक्त किया जा सकता है।

var distinctItems = items 
     .GroupBy(x => x.PropertyToCompare) 
     .Select(x => x.First()); 
+0

यह बहुत अच्छा काम किया। धन्यवाद। –

+0

कृपया केवल लिंक करके जवाब न दें। उत्तर में प्रासंगिक कोड शामिल है। –

+1

हाँ, मैं अब और नहीं करता लेकिन 2010 में मैंने इस अभ्यास पर ध्यान नहीं दिया। – Stilgar

4

कोशिश एक IQualityComparer

public class MyObjEqualityComparer : IEqualityComparer<MyObj> 
{ 
    public bool Equals(MyObj x, MyObj y) 
    { 
     return x.Category.Equals(y.Category) && 
       x.Country.Equals(y.Country); 
    } 

    public int GetHashCode(MyObj obj) 
    { 
     return obj.GetHashCode(); 
    } 
} 

तो यहाँ

var comparer = new MyObjEqualityComparer(); 
myObjs.Where(m => m.SomeProperty == "whatever").Distinct(comparer); 
+0

मुझे यह समाधान पसंद है, हालांकि मुझे इसके साथ कोई समस्या थी। GetHashCode इसे मैचों को नहीं ढूंढ रहा था। मुझे इसे वापस लौटना पड़ा जैसे 'वापसी obj.Category.GetHashCode() + obj.Country.GetHashCode() ' –

3

का उपयोग स्पष्टीकरण के लिए, अन्य उत्तर पर एक नज़र डालें। मैं सिर्फ इस मुद्दे को संभालने का एक तरीका प्रदान कर रहा हूं।

आप this पसंद कर सकते हैं:

public class LambdaComparer<T>:IEqualityComparer<T>{ 
    private readonly Func<T,T,bool> _comparer; 
    private readonly Func<T,int> _hash; 
    public LambdaComparer(Func<T,T,bool> comparer): 
    this(comparer,o=>0) {} 
    public LambdaComparer(Func<T,T,bool> comparer,Func<T,int> hash){ 
    if(comparer==null) throw new ArgumentNullException("comparer"); 
    if(hash==null) throw new ArgumentNullException("hash"); 
    _comparer=comparer; 
    _hash=hash; 
    } 
    public bool Equals(T x,T y){ 
    return _comparer(x,y); 
    } 
    public int GetHashCode(T obj){ 
    return _hash(obj); 
    } 
} 

उपयोग:

public void Foo{ 
    public string Fizz{get;set;} 
    public BarEnum Bar{get;set;} 
} 

public enum BarEnum {One,Two,Three} 

var lst=new List<Foo>(); 
lst.Distinct(new LambdaComparer<Foo>(
    (x1,x2)=>x1.Fizz==x2.Fizz&& 
      x1.Bar==x2.Bar)); 

तुम भी इसके चारों ओर लपेट शोर new LambdaComparer<T>(...) बात लिख से बचने के लिए कर सकते हैं:

public static class EnumerableExtensions{ 
public static IEnumerable<T> SmartDistinct<T> 
    (this IEnumerable<T> lst, Func<T, T, bool> pred){ 
    return lst.Distinct(new LambdaComparer<T>(pred)); 
} 
} 

उपयोग:

lst.SmartDistinct((x1,x2)=>x1.Fizz==x2.Fizz&&x1.Bar==x2.Bar); 

एनबी: केवल Linq2Objects

1

तुम गलत यह नहीं कर रहे हैं के लिए मज़बूती से काम करता है, यह .NET फ्रेमवर्क में .Distinct() का सिर्फ बुरा कार्यान्वयन है।

एक तरह से इसे ठीक करने के पहले से ही अन्य उत्तर में दिखाया गया है, लेकिन वहाँ भी जो लाभ यह है कि आप वस्तु के हैश tweak बिना आसानी से हर जगह एक विस्तार विधि के रूप में उपयोग कर सकते हैं उपलब्ध एक छोटी समाधान, है मान।

इस पर एक नज़र डालें:


उपयोग:

var myQuery=(from x in Customers select x).MyDistinct(d => d.CustomerID); 

नोट: यह उदाहरण एक डेटाबेस क्वेरी का उपयोग करता है, लेकिन यह भी एक गणनीय वस्तु सूची के साथ काम करता है।


MyDistinct की घोषणा:

public static class Extensions 
{ 
    public static IEnumerable<T> MyDistinct<T, V>(this IEnumerable<T> query, 
                Func<T, V> f) 
    { 
     return query.GroupBy(f).Select(x=>x.First()); 
    } 
} 

और यह सब कुछ के लिए काम करता है, संस्थाओं के रूप में रूप में अच्छी तरह वस्तुओं।यदि आवश्यक हो, तो आप ऊपर दिए गए उदाहरण में वापसी प्रकार और पहले पैरामीटर प्रकार को प्रतिस्थापित करके IQueryable<T> के लिए दूसरी ओवरलोडेड एक्सटेंशन विधि बना सकते हैं।

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