简体   繁体   English

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

[英]How to return a specific item in Distinct using EqualityComparer in C#

I have defined a CustomListComparer which compares List<int> A and List<int> B and if Union of the two lists equals at least on of the lists, considers them equal. 我已经定义了一个CustomListComparer ,用于比较List<int> AList<int> B ,如果两个列表的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);
}

For example, the below lists are equal: 例如,以下列表是相同的:

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

And the below lists are NOT: 以下列表不是:

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

Now all this works fine. 现在一切正常。 But here is my question: Which one of the Lists (A or B) gets into distinctLists ? 但这是我的问题:哪一个列表(A或B)进入distinctLists Do I have any say in that? 我有什么发言权吗? Or is it all handled by compiler itself? 或者这一切都由编译器本身处理?

What I mean is say that the EqualityComparer considers both of the Lists equal. 我的意思是说EqualityComparer认为两个列表相等。 and adds one of them to distinctLists . 并将其中一个添加到distinctLists Which one does it add? 它添加了哪一个? I want the list with more items to be added. 我想要添加更多项目的列表。

Distinct always adds the first element which it see. Distinct总是添加它看到的第一个元素。 So it depends on the order of the sequence which you passed in. 所以它取决于你传入的序列的顺序。

Source is fairly simple, which can be found here 来源相当简单,可以在这里找到

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;
}

If you need to return list with more elements, you need to roll your own. 如果您需要返回包含更多元素的列表,则需要自行滚动。 Worth noting that Distinct is lazy, but the implementation you're asking for will need a eager implementation. 值得注意的是, 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;
        }
    }
}

Updated the answer with naive implementation, not tested though. 使用天真的实现更新了答案,但未经过测试。

Instead of Distinct you can use GroupBy with MaxBy method:: 您可以将GroupByMaxBy方法一起使用而不是Distinct ::

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

This will group lists using your comparer and select the list that has max item from each group. 这将使用比较器对列表进行分组,并选择每个组中包含最大项目的列表。

MaxBy is quite useful in this situation, you can find it in MoreLINQ library. MaxBy在这种情况下非常有用,您可以在MoreLINQ库中找到它。

Edit: Using pure LINQ: 编辑:使用纯LINQ:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM