引自:http://blog.csdn.net/shaopengfei/article/details/36426763
從C# 3.0開始提供了Distinct方法,這對於集合的使用有了更為豐富的方法,經過在網上搜索相應的資源,發現有關這方面的寫的好的文章還是不少的。而且為了擴展Linq的使用不方便的地方,有一些辦法非常有效。由於本人工作中的需要,有一些功能暫時沒有用到那么深入,現在只把最簡單的一些功能分享出來,整理出來。
-
簡單一維集合的使用:
- List<int> ages = new List<int> { 21, 46, 46, 55, 17, 21, 55, 55 };
- List<string> names = new List<string> { "wang", "li", "zhang", "li", "wang", "chen", "he", "wang" };
- IEnumerable<int> distinctAges = ages.Distinct();
- Console.WriteLine("Distinct ages:");
- foreach (int age in distinctAges)
- {
- Console.WriteLine(age);
- }
- var distinctNames = names.Distinct();
- Console.WriteLine("\nDistinct names:");
- foreach (string name in distinctNames)
- {
- Console.WriteLine(name);
- }
- 在這段代碼中,是最簡單的Distinct()方法的使用。使用了集合接口IEnumerable,以及隱式類型var,至於這兩種用法有什么區別,沒有研究出來。
- 但是如果象下面這樣的代碼,是錯誤的!
- List<int> disAge = ages.Distinct();
- 正確的方法應該是:
- List<int> ages = new List<int> { 21, 46, 46, 55, 17, 21, 55, 55 };
- List<int> disAge = ages.Distinct().ToList();
- foreach (int a in disAge)
- Console.WriteLine(a);
- 也就是說Distinct()方法的返回集合類型是一個接口,不是具體的集合,所以需要用一個ToList()。
-
自定義類的使用:
- 首先我們看MSDN上給出的例子,先定義一個產品類:
- public class Product : IEquatable<Product>
- {
- public string Name { get; set; }
- public int Code { get; set; }
- public bool Equals(Product other)
- {
- //Check whether the compared object is null.
- if (Object.ReferenceEquals(other, null)) return false;
- //Check whether the compared object references the same data.
- if (Object.ReferenceEquals(this, other)) return true;
- //Check whether the products' properties are equal.
- return Code.Equals(other.Code) && Name.Equals(other.Name);
- }
- // If Equals() returns true for a pair of objects
- // then GetHashCode() must return the same value for these objects.
- public override int GetHashCode()
- {
- //Get hash code for the Name field if it is not null.
- int hashProductName = Name == null ? 0 : Name.GetHashCode();
- //Get hash code for the Code field.
- int hashProductCode = Code.GetHashCode();
- //Calculate the hash code for the product.
- return hashProductName ^ hashProductCode;
- }
- }
- 在主函數里,是這樣用的:
- static void Main(string[] args)
- {
- Product[] products =
- {
- new Product { Name = "apple", Code = 9 },
- new Product { Name = "orange", Code = 4 },
- new Product { Name = "apple", Code = 9 },
- new Product { Name = "lemon", Code = 12 }
- };
- //Exclude duplicates.
- IEnumerable<Product> noduplicates =
- products.Distinct();
- foreach (var product in noduplicates)
- Console.WriteLine(product.Name + " " + product.Code);
- }
- 這樣的輸出是:
- /*
- This code produces the following output:
- apple 9
- orange 4
- lemon 12
- */
- 但是現在的問題是,如果我們把主函數里改成這樣:
- static void Main(string[] args)
- {
- Product[] products =
- {
- new Product { Name = "Smallapple", Code = 9 },
- new Product { Name = "orange", Code = 4 },
- new Product { Name = "Bigapple", Code = 9 },
- new Product { Name = "lemon", Code = 12 }
- };
- //Exclude duplicates.
- IEnumerable<Product> noduplicates =
- products.Distinct();
- foreach (var product in noduplicates)
- Console.WriteLine(product.Name + " " + product.Code);
- }
- 這樣的輸出是:
- /*
- This code produces the following output:
- Smallapple 9
- orange 4
- Bigapple 9
- lemon 12
- */
- 我們的問題是,如果想按Code來索引,想找出Code唯一的這些成員,那么這里就需要重新定義一個對Code比較的類,或者再擴展成泛型類,但是這樣非常繁瑣。
-
博客鶴沖天的改進辦法(以下均轉自這個博客)
- 首先,創建一個通用比較的類,實現IEqualityComparer<T>接口:
- public class CommonEqualityComparer<T, V> : IEqualityComparer<T>
- {
- private Func<T, V> keySelector;
- public CommonEqualityComparer(Func<T, V> keySelector)
- {
- this.keySelector = keySelector;
- }
- public bool Equals(T x, T y)
- {
- return EqualityComparer<V>.Default.Equals(keySelector(x), keySelector(y));
- }
- public int GetHashCode(T obj)
- {
- return EqualityComparer<V>.Default.GetHashCode(keySelector(obj));
- }
- }
- 借助上面這個類,Distinct擴展方法就可以這樣寫:
- public static class DistinctExtensions
- {
- public static IEnumerable<T> Distinct<T, V>(this IEnumerable<T> source, Func<T, V> keySelector)
- {
- return source.Distinct(new CommonEqualityComparer<T, V>(keySelector));
- }
- }
- 下面的使用就很簡單了:
- Product[] products =
- {
- new Product { Name = "Smallapple", Code = 9 },
- new Product { Name = "orange", Code = 4 },
- new Product { Name = "Bigapple", Code = 9 },
- new Product { Name = "lemon", Code = 12 }
- };
- var p1 = products.Distinct(p => p.Code);
- foreach (Product pro in p1)
- Console.WriteLine(pro.Name + "," + pro.Code);
- var p2 = products.Distinct(p => p.Name);
- foreach (Product pro in p2)
- Console.WriteLine(pro.Name + "," + pro.Code);
- 可以看到,加上Linq表達式,可以方便的對自定義類的任意字段進行Distinct的處理。