3

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.

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? 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. and adds one of them to distinctLists. Which one does it add? I want the list with more items to be added.

Vahid
  • 5,144
  • 13
  • 70
  • 146

2 Answers2

1

Distinct always adds the first element which it see. 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.

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.

Sriram Sakthivel
  • 72,067
  • 7
  • 111
  • 189
  • Thanks Sriram for the source. Can you be more specific on how can implement that? I have trouble understanding this. – Vahid Jan 05 '15 at 11:30
  • 1
    @Vahid Updated the answer with naive implementation, I've not tested it. If there is a problem drop me a comment. – Sriram Sakthivel Jan 05 '15 at 11:47
  • I had trouble implementing it. `var distinctList = MyLists.DistinctMaxElements(new CustomListComparer()).ToList()`; – Vahid Jan 05 '15 at 11:51
  • Post your code for `CustomListComparer`, and you said trouble implementing it, but never said what's the trouble? What happens? Compiler error? Post the [MVCE](http://stackoverflow.com/help/mcve) please. – Sriram Sakthivel Jan 05 '15 at 11:54
1

Instead of Distinct you can use GroupBy with MaxBy method::

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.

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();
Selman Genç
  • 100,147
  • 13
  • 119
  • 184
  • Thanks Selman, but I'm not using MoreLinq, can this be done using Linq? – Vahid Jan 05 '15 at 11:42
  • 1
    @Vahid ofcourse, added that solution as well. but it won't be as effiecient as the first solution. – Selman Genç Jan 05 '15 at 11:45
  • Thank you so much Selman. This is actually working very well. And this is the method I used in my code actually. To be consistent with the question I chose Sriram Sakthivel's answer which is also working well. – Vahid Jan 05 '15 at 11:58