如何在 C# 中使用 EqualityComparer return Distinct 中的特定项目
How to return a specific item in Distinct using EqualityComparer in C#
我定义了一个 CustomListComparer
来比较 List<int> A
和 List<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);
}
例如,下面的列表是相等的:
ListA = {1,2,3}
ListB = {1,2,3,4}
下面的列表不是:
ListA = {1,5}
ListB = {1,2,3,4}
现在一切正常。但这是我的问题:列表(A 或 B)中的哪一个进入 distinctLists
?我对此有发言权吗?还是全部由编译器自己处理?
我的意思是说 EqualityComparer
认为两个列表相等。并将其中之一添加到 distinctLists
。它添加了哪一个? 我想要添加更多项目的列表。
Distinct
总是添加它看到的第一个元素。所以这取决于你传入的序列的顺序。
来源比较简单,可以是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;
}
如果您需要 return 包含更多元素的列表,您需要自己滚动。值得注意的是 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;
}
}
}
用简单的实现更新了答案,虽然没有测试。
您可以使用 GroupBy
和 MaxBy
方法来代替 Distinct
::
var distinctLists = MyLists.GroupBy(x => x, new CustomListComparer())
.Select(g => g.MaxBy(x => x.Count))
.ToList();
这将使用您的比较器对列表进行分组,select每个组中包含最大项目的列表。
MaxBy
在这种情况下非常有用,你可以在 MoreLINQ 库中找到它。
编辑: 使用纯 LINQ:
var distinctLists = MyLists.GroupBy(x => x, new CustomListComparer())
.Select(g => g.First(x => x.Count == g.Max(l => l.Count)))
.ToList();
我定义了一个 CustomListComparer
来比较 List<int> A
和 List<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);
}
例如,下面的列表是相等的:
ListA = {1,2,3}
ListB = {1,2,3,4}
下面的列表不是:
ListA = {1,5}
ListB = {1,2,3,4}
现在一切正常。但这是我的问题:列表(A 或 B)中的哪一个进入 distinctLists
?我对此有发言权吗?还是全部由编译器自己处理?
我的意思是说 EqualityComparer
认为两个列表相等。并将其中之一添加到 distinctLists
。它添加了哪一个? 我想要添加更多项目的列表。
Distinct
总是添加它看到的第一个元素。所以这取决于你传入的序列的顺序。
来源比较简单,可以是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;
}
如果您需要 return 包含更多元素的列表,您需要自己滚动。值得注意的是 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;
}
}
}
用简单的实现更新了答案,虽然没有测试。
您可以使用 GroupBy
和 MaxBy
方法来代替 Distinct
::
var distinctLists = MyLists.GroupBy(x => x, new CustomListComparer())
.Select(g => g.MaxBy(x => x.Count))
.ToList();
这将使用您的比较器对列表进行分组,select每个组中包含最大项目的列表。
MaxBy
在这种情况下非常有用,你可以在 MoreLINQ 库中找到它。
编辑: 使用纯 LINQ:
var distinctLists = MyLists.GroupBy(x => x, new CustomListComparer())
.Select(g => g.First(x => x.Count == g.Max(l => l.Count)))
.ToList();