How to return a specific element in Distinct using EqualityComparer in C #

I have defined a CustomListComparer

that compares List<int> A

and List<int> B

, and if Union

the two lists are equal, at least the lists are equal.

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 following lists are equal:

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

      

And below are NOT listed:

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

      

It's all fine now. But here's my question: which of the lists (A or B) falls into distinctLists

? Do I have any words? Or is it all handled by the compiler itself?

I mean, I EqualityComparer

think both lists are equal. and adds one of them to distinctLists

. Which one does he add? I want more items to be added to the list.

+3


source to share


2 answers


Distinct

always adds the first item it sees. So it depends on the order of the sequence you went through.

The source is pretty 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 a list with a lot of items, you need to cast your own. It's worth noting that being Distinct

lazy, but the implementation you are asking for will require energetic implementation.

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 answer with a naive implementation, but not tested.

+1


source


Instead, Distinct

you can use GroupBy

with the method MaxBy

::

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

      

This will group the lists with your comparator and select a list that has the maximum item from each group.



MaxBy

very useful in this situation, you can find it in the MoreLINQ library.

Edit: Using pure LINQ:

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

      

+1


source







All Articles