List.Distinct() 可以应用于 List> 的列表类型吗?

本文关键字:List 列表 类型 Distinct String 应用于 | 更新日期: 2023-09-27 18:27:22

List<List<String>> ls = new List<List<String>>();
List<String> l1 = new List<String>();
l1.Add("Peter");
l1.Add("123");
ls.Add(l1);
List<String> l2 = new List<String>();
l2.Add("Peter");
l2.Add("123");
ls.Add(l2);
ls = ls.Distinct().ToList();

我想ls中只有一个元素,但实际上仍然有2个元素。可能的原因是什么?

List.Distinct() 可以应用于 List<List<String>> 的列表类型吗?

这是因为List<T>没有Equals并且GetHashCode实现的,因此正在执行标准引用比较。它返回 false,因为你有两个单独的列表。

您可以编写自己的IEqualityComparer<List<string>>实现,并将其作为方法参数提供Distinct。在比较器中,您可以使用 Enumerable.SequenceEqual ( 方法来检查列表是否具有相同的内容。

对于您的情况,您必须构建自定义比较器来实现接口IEqualityComparer<List<string>>,并使用SequenceEqualEqual方法中进行比较:

public class CustomComparer : IEqualityComparer<List<string>>
{
    public bool Equals(List<string> x, List<string> y)
    {
        return x.SequenceEqual(y);
    }
    public int GetHashCode(List<string> obj)
    {
        int hashCode = 0;
        foreach (string str in obj)
        {
            hashCode ^= str.GetHashCode();
        }
        return hashCode;
    }
}

然后:

ls = ls.Distinct(new CustomComparer()).ToList();

使用GroupBy区分的另一种棘手方法

       ls = ls.GroupBy(x => string.Join("", x))
              .Select(g => g.First())
              .ToList();

List 使用的比较基于引用比较。由于这两个列表是不同的实例,因此它们并不相同,并且不同认为它们是不同的。

如果需要非重复值,可以使用.SelectMany()选择父列表内每个列表中的字符串:

var list = new List<List<String>>();
var list1 = new List<String>();
list1.Add("Peter");
list1.Add("123");
list.Add(list1);
var list2 = new List<String>();
list2.Add("Peter");
list2.Add("123");
list.Add(list2);
var distinct = list.SelectMany(x => x).Distinct().ToList();
distinct.ForEach(x => Console.WriteLine(x));