如何使用 C# 中的 EqualityComparer 返回 Distinct 中的特定项

本文关键字:Distinct 返回 何使用 中的 EqualityComparer | 更新日期: 2023-09-27 18:36:27

我定义了一个比较List<int> AList<int> BCustomListComparer,如果两个列表中的Union至少在列表中相等,则认为它们相等。

var distinctLists = MyLists.Distinct(new CustomListComparer()).ToList();
public bool Equals(Frame other)
{
    var union = CustomList.Union(other.CustomList).ToList();
    return union.SequenceEqual(CustomList) ||
           union.SequenceEqual(other.CustomList);
}

例如,以下列表是相等的:

ListA = {1,2,3}
ListB = {1,2,3,4}

下面的列表不是:

ListA = {1,5}
ListB = {1,2,3,4}

现在这一切都工作正常。但这是我的问题:哪个列表(A 或 B)进入distinctLists?我对此有什么发言权吗?还是全部由编译器本身处理?

我的意思是说,EqualityComparer认为两个列表是平等的。 并将其中一个添加到distinctLists .它添加了哪一个?我希望添加包含更多项目的列表。

如何使用 C# 中的 EqualityComparer 返回 Distinct 中的特定项

Distinct总是添加它看到的第一个元素。因此,这取决于您传入的序列的顺序。

来源相当简单,可以在这里找到

static IEnumerable<TSource> DistinctIterator<TSource>(IEnumerable<TSource> source, IEqualityComparer<TSource> comparer) {
    Set<TSource> set = new Set<TSource>(comparer);
    foreach (TSource element in source)
        if (set.Add(element)) yield return element;
}

如果您需要返回包含更多元素的列表,则需要滚动自己的元素。值得注意的是,Distinct是懒惰的,但你要求的实现需要一个热切的实现。

static class MyDistinctExtensions
{
    public static IEnumerable<T> DistinctMaxElements<T>(this IEnumerable<T> source, IEqualityComparer<T> comparer) where T : ICollection
    {
        Dictionary<T, List<T>> dictionary = new Dictionary<T, List<T>>(comparer);
        foreach (var item in source)
        {
            List<T> list;
            if (!dictionary.TryGetValue(item, out list))
            {
                list = new List<T>();
                dictionary.Add(item, list);
            }
            list.Add(item);
        }
        foreach (var list in dictionary.Values)
        {
            yield return list.Select(x => new { List = x, Count = x.Count })
                .OrderByDescending(x => x.Count)
                .First().List;
        }
    }
}

用朴素的实现更新了答案,虽然没有经过测试。

而不是Distinct您可以使用MaxBy方法使用GroupBy

var distinctLists = MyLists.GroupBy(x => x, new CustomListComparer())
                           .Select(g => g.MaxBy(x => x.Count))
                           .ToList();

这将使用比较器对列表进行分组,并从每个组中选择具有最大项目的列表。

MaxBy在这种情况下非常有用,您可以在 MoreLINQ 库中找到它。

编辑:使用纯 LINQ:

var distinctLists = MyLists.GroupBy(x => x, new CustomListComparer())
                           .Select(g => g.First(x => x.Count == g.Max(l => l.Count)))
                           .ToList();