LINQ

2010-03-29 6 views
97

साथ वर्ग की संपत्ति से अलग मैं एक संग्रह है।LINQ

मेरे पास संग्रह में तीन कारें हैं, और दो समान कारकोड के साथ हैं।

मैं इस संग्रह को अद्वितीय कारकोड के साथ कारों में बदलने के लिए LINQ का उपयोग कैसे कर सकता हूं?

उत्तर

183

आप समूह का उपयोग कर सकते हैं, और प्रत्येक से पहले कार मिल समूह:

List<Car> distinct = 
    cars 
    .GroupBy(car => car.CarCode) 
    .Select(g => g.First()) 
    .ToList(); 
+0

@NateGates: मैं उस व्यक्ति से बात कर रहा था जो दो दिन पहले डाउनवॉट किया गया था। – Guffa

+0

मुझे लगता है कि कोई ओवरहेड मौजूद नहीं है! –

+5

@AmirHosseinMehrvarzi: समूह के निर्माण के रूप में कुछ ओवरहेड है, और फिर प्रत्येक समूह से केवल एक आइटम का उपयोग किया जाता है। – Guffa

90

उपयोग MoreLINQ है, जो एक DistinctBy विधि :)

IEnumerable<Car> distinctCars = cars.DistinctBy(car => car.CarCode); 

है (यह ध्यान रखें कि आप वस्तुओं को केवल LINQ के लिए है।)

+3

बस लिंक प्रदान कर रहा है! Http: //code.google.com/p/morelinq/source/browse/MoreLinq/? R = d4396b9ff63932be0ab07c36452a481d20f96307 – Diogo

+1

हाय जॉन, यदि मैं कर सकता हूं तो दो प्रश्न। 1) आप पुस्तकालय को Nuget में क्यों नहीं जोड़ते? 2) LINQ से SQL \ EF \ NH के बारे में क्या? हम इसे कैसे कार्यान्वित कर सकते हैं? क्या हमें गुफा संस्करण का उपयोग करना है (यदि आपका संस्करण 'NO_HASHSET' सत्य है ...) है? आपका बहुत बहुत धन्यवाद! – gdoron

+2

@gdoron: 1) यह पहले से ही NuGet में है: http://www.nuget.org/packages/morelinq 2) मुझे संदेह है कि LINQ से SQL आदि उस अनुमति देने के लिए पर्याप्त लचीला हैं। –

25

आप एक IEqualityComparer लागू करना और उपयोग है कि अपने विशिष्ट विस्तार में कर सकते हैं।

class CarEqualityComparer : IEqualityComparer<Car> 
{ 
    #region IEqualityComparer<Car> Members 

    public bool Equals(Car x, Car y) 
    { 
     return x.CarCode.Equals(y.CarCode); 
    } 

    public int GetHashCode(Car obj) 
    { 
     return obj.CarCode.GetHashCode(); 
    } 

    #endregion 
} 

और फिर

var uniqueCars = cars.Distinct(new CarEqualityComparer()); 
+0

हम इसे बिना लिखने के कैसे उपयोग कर सकते हैं: नई CarEqualityComparer()? – Parsa

1

एक और तरीका है एक ही बात को पूरा करने के ...

List<Car> distinticBy = cars 
    .Select(car => car.CarCode) 
    .Distinct() 
    .Select(code => cars.First(car => car.CarCode == code)) 
    .ToList(); 

यह एक अधिक सामान्य तरीके से यह करने के लिए एक विस्तार विधि बनाने के लिए संभव है। यह दिलचस्प होगा अगर कोई ग्रुपबी दृष्टिकोण के खिलाफ इस 'DistinctBy' के प्रदर्शन को बेकार कर सकता है।

+0

दूसरा 'चयन' एक ओ (एन * एम) ऑपरेशन होगा, जिससे यह अच्छी तरह से स्केल नहीं होगा। यदि बहुत सारे डुप्लिकेट हैं तो यह बेहतर प्रदर्शन कर सकता है, यानी यदि पहले 'चयन' का परिणाम मूल संग्रह का एक बहुत ही छोटा हिस्सा है। – Guffa

30

Guffa रूप में, लेकिन एक विस्तार पद्धति के रूप में एक ही दृष्टिकोण:

var uniqueCars = cars.DistinctBy(x => x.CarCode); 
1

तुम मेरे PowerfulExtensions पुस्तकालय की जाँच कर सकते हैं:

public static IEnumerable<T> DistinctBy<T, TKey>(this IEnumerable<T> items, Func<T, TKey> property) 
{ 
    return items.GroupBy(property).Select(x => x.First()); 
} 

रूप में प्रयुक्त। वर्तमान में यह एक बहुत ही युवा चरण में है, लेकिन पहले से ही आप अलग-अलग गुणों को छोड़कर अलग, संघ, अंतर, विधियों का उपयोग कर सकते हैं;

इस तरह आप इसका इस्तेमाल:

using PowerfulExtensions.Linq; 
... 
var distinct = myArray.Distinct(x => x.A, x => x.B); 
+0

यदि मेरे पास ऑब्जेक्ट्स की एक सूची है जहां मैं एक ही आईडी के साथ सभी ऑब्जेक्ट्स को हटाना चाहता हूं, तो यह 'myList.Distinct (x => x.ID)' होगा? – Thomas

3

Linq करने वाली वस्तुओं का एक अन्य एक्सटेंशन पद्धति का उपयोग GroupBy बिना:

/// <summary> 
    /// Returns the set of items, made distinct by the selected value. 
    /// </summary> 
    /// <typeparam name="TSource">The type of the source.</typeparam> 
    /// <typeparam name="TResult">The type of the result.</typeparam> 
    /// <param name="source">The source collection.</param> 
    /// <param name="selector">A function that selects a value to determine unique results.</param> 
    /// <returns>IEnumerable&lt;TSource&gt;.</returns> 
    public static IEnumerable<TSource> Distinct<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TResult> selector) 
    { 
     HashSet<TResult> set = new HashSet<TResult>(); 

     foreach(var item in source) 
     { 
      var selectedValue = selector(item); 

      if (set.Add(selectedValue)) 
       yield return item; 
     } 
    } 
3

मैं प्रदर्शन के संदर्भ में सबसे अच्छा विकल्प लगता है (या किसी भी शर्तों में) IEqualityComparer इंटरफ़ेस का उपयोग करके अलग करना है।

हालांकि हर बार प्रत्येक वर्ग के लिए एक नया तुलनाकर्ता लागू करना बोझिल होता है और बॉयलरप्लेट कोड उत्पन्न करता है।

तो यहां एक विस्तार विधि है जो प्रतिबिंब का उपयोग कर किसी भी वर्ग के लिए फ्लाई पर एक नया IEqualityComparer उत्पन्न करती है।

उपयोग:

var filtered = taskList.DistinctBy(t => t.TaskExternalId).ToArray(); 

एक्सटेंशन विधि संहिता

public static class LinqExtensions 
{ 
    public static IEnumerable<T> DistinctBy<T, TKey>(this IEnumerable<T> items, Func<T, TKey> property) 
    { 
     GeneralPropertyComparer<T, TKey> comparer = new GeneralPropertyComparer<T,TKey>(property); 
     return items.Distinct(comparer); 
    } 
} 
public class GeneralPropertyComparer<T,TKey> : IEqualityComparer<T> 
{ 
    private Func<T, TKey> expr { get; set; } 
    public GeneralPropertyComparer (Func<T, TKey> expr) 
    { 
     this.expr = expr; 
    } 
    public bool Equals(T left, T right) 
    { 
     var leftProp = expr.Invoke(left); 
     var rightProp = expr.Invoke(right); 
     if (leftProp == null && rightProp == null) 
      return true; 
     else if (leftProp == null^rightProp == null) 
      return false; 
     else 
      return leftProp.Equals(rightProp); 
    } 
    public int GetHashCode(T obj) 
    { 
     var prop = expr.Invoke(obj); 
     return (prop==null)? 0:prop.GetHashCode(); 
    } 
} 
+0

यहां प्रतिबिंब कहां है? – MistyK

0

आप प्रभावी रूप से वस्तुओं का संग्रह पर Distinct उपयोग नहीं कर सकते (अतिरिक्त कार्य के बिना)। मैं समझाऊंगा क्यों।

The documentation says:

यह डिफ़ॉल्ट समानता comparer, Default, मानों की तुलना करने का उपयोग करता है।

ऑब्जेक्ट्स के लिए इसका अर्थ यह है कि यह वस्तुओं की तुलना करने के लिए डिफ़ॉल्ट समीकरण विधि का उपयोग करता है (source)। यह उनके हैश कोड पर है। और चूंकि आपकी वस्तुएं GetHashCode() और Equals विधियों को लागू नहीं करती हैं, इसलिए यह ऑब्जेक्ट के संदर्भ पर जांच करेगी, जो अलग नहीं हैं।

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