不同于linq的类的属性

我有一个集合:

List<Car> cars = new List<Car>(); 

汽车是由他们的财产CarCode唯一标识。

我有三辆车在收集,和两个相同的CarCodes。

我如何使用LINQ将这个集合转换成独特的CarCodes的汽车?

您可以使用分组,并从每组获得第一辆车:

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

使用MoreLINQ ,其中有一个DistinctBy方法:)

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

(这只适用于LINQ to Objects,请注意。)

与Guffa一样的方法,但作为扩展方法:

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

用作:

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

您可以实现一个IEqualityComparer,并将其用于Distinct扩展。

 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()); 

我认为在性能方面(或任何方面)的最佳select是使用IEqualityComparer接口区分。

虽然每次为每个类实现一个新的比较器都很麻烦,并产生样板代码。

所以这里是一个扩展方法,它使用reflection为任何类生成一个新的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(); } } 

Linq-to-Objects的另一种扩展方法,不使用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; } } 

另一种方法来完成相同的事情…

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

可以创build一个扩展方法以更通用的方式来完成此操作。 如果有人能够评估这个“DistinctBy”对GroupBy方法的performance,这将是有趣的。

你可以看看我的PowerfulExtensions库。 目前处于一个非常年轻的阶段,但已经可以使用像Distinct,Union,Intersect等方法,除了任何数量的属性,

这是你如何使用它:

 using PowerfulExtensions.Linq; ... var distinct = myArray.Distinct(x => xA, x => xB); 

你不能有效地使用Distinct对象的集合(没有额外的工作)。 我会解释为什么。

该文件说 :

它使用默认的相等比较器Default来比较值。

对于这意味着它使用默认方程方法来比较对象( 源 )。 这是他们的哈希码。 而且由于你的对象没有实现GetHashCode()Equals方法,所以它会检查对象的引用,这些引用是不清楚的。