与LINQ类的属性不同

use*_*618 152 c# linq distinct

我有一个集合:

List<Car> cars = new List<Car>();
Run Code Online (Sandbox Code Playgroud)

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

我收集了三辆汽车,两辆汽车编码相同.

如何使用LINQ将此集合转换为具有唯一CarCodes的Cars?

Guf*_*ffa 268

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

List<Car> distinct =
  cars
  .GroupBy(car => car.CarCode)
  .Select(g => g.First())
  .ToList();
Run Code Online (Sandbox Code Playgroud)

  • 更多的密钥写:.GroupBy(car => new {car.CarCode,car.PID,car.CID}) (12认同)
  • .NET 6 现在有 `DistinctBy` (https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.distinctby?view=net-6.0) (8认同)
  • @AmirHosseinMehrvarzi:创建组时会有一些开销,然后只使用每个组中的一个项目. (6认同)
  • @Nani通常来说您是对的,但是由于只有在集合中有匹配的元素时才会创建一个组,因此每个组至少有一个元素。-&gt;在这种用例中,`First()`完全可以。 (3认同)

Jon*_*eet 116

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

IEnumerable<Car> distinctCars = cars.DistinctBy(car => car.CarCode);
Run Code Online (Sandbox Code Playgroud)

(请注意,这仅适用于LINQ to Objects.)

  • 只提供链接!http://code.google.com/p/morelinq/source/browse/MoreLinq/?r = d4396b9ff63932be0ab07c36452a481d20f96307 (4认同)
  • @Shimmy:我个人对在"System"下编写代码感到紧张,因为这给人一种错误的印象,认为它是"官方的".但是你的口味可能会有所不同,当然:) (3认同)
  • @gdoron:1)它已经在NuGet中:http://www.nuget.org/packages/morelinq 2)我怀疑LINQ to SQL等是否具有足够的灵活性以允许它. (2认同)

She*_*ror 44

与Guffa相同的方法,但作为扩展方法:

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

用作:

var uniqueCars = cars.DistinctBy(x => x.CarCode);
Run Code Online (Sandbox Code Playgroud)

  • 完善。Microsoft.Ajax.Utilities库上也提供了相同的方法。 (2认同)

Ant*_*ram 29

您可以实现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
}
Run Code Online (Sandbox Code Playgroud)

然后

var uniqueCars = cars.Distinct(new CarEqualityComparer());
Run Code Online (Sandbox Code Playgroud)

  • @Parsa您可以创建一个接受lambdas的IEqualitiyComparer包装器类型.这将使其概括:`cars.Distinct(new GenericEqualityComparer <Car>((a,b)=> a.CarCode == b.CarCode,x => x.CarCode.GetHashCode()))`.我过去曾经使用过这种方法,因为它有时会在执行一次性的Distinct时增加价值. (2认同)

Luk*_*ett 7

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;
        }
    }
Run Code Online (Sandbox Code Playgroud)


Ane*_*lou 5

我认为性能方面(或任何术语)的最佳选择是使用IEqualityComparer接口进行区分.

虽然每次实现每个类的新比较器都很麻烦并且生成样板代码.

所以这里有一个扩展方法,可以为使用反射的任何类动态生成新的IEqualityComparer.

用法:

var filtered = taskList.DistinctBy(t => t.TaskExternalId).ToArray();
Run Code Online (Sandbox Code Playgroud)

扩展方法代码

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();
    }
}
Run Code Online (Sandbox Code Playgroud)