这是一个非常简单的问题,它肯定已经被提出并得到了回答……但是我找不到它。

我想使用LINQ从值类型列表中删除重复项。我尝试了以下方法:

List<List<int>> a = new List<List<int>>() { new List<int>() { 1, 2, 3 }, new List<int>() { 1, 2, 3 }, new List<int>() { 2, 3, 4 } };
// remove duplicates from a
List<List<int>> b = a.Distinct().ToList(); // this doesn't do it
List<List<int>> c = a.Distinct(new ListKeyComparer<int>()).ToList(); // nor does this

internal class ListKeyComparer<TKey> : IEqualityComparer<List<TKey>>
{
  public bool Equals(List<TKey> key1, List<TKey> key2)
  {
    return String.Join("_", key1).Equals(String.Join("_", key2));
  }

  public int GetHashCode(List<TKey> key)
  {
    return key.GetHashCode();
  }
}


欢迎所有解决方案!

最佳答案

您的实现的问题在于它使用了straight列表的GetHashCode key。您可以通过将其替换为您所构造的“关键字字符串”的哈希码来解决它,该哈希码是通过在数字之间加上下划线或通过动态计算哈希码来构造的:

// Here is a fix to your method. It would work if TKey values
// cannot have underscores. In any event, it will be very slow.
internal class ListKeyComparer<TKey> : IEqualityComparer<List<TKey>>
{
  // Make a method that produces the key to avoid repeating yourself:
  private string MakeKey(List<TKey> key) {
    return String.Join("_", key);
  }
  public bool Equals(List<TKey> key1, List<TKey> key2)
  {
    return MakeKey(key1).Equals(MakeKey(key2));
  }

  public int GetHashCode(List<TKey> key)
  {
    return MakeKey(key).GetHashCode();
  }
}


这是一个更好的实现:

internal class ListKeyComparer<TKey> : IEqualityComparer<List<TKey>>
{
  public bool Equals(List<TKey> key1, List<TKey> key2)
  {
    return key1.SequenceEqual(key2);
  }

  public int GetHashCode(List<TKey> key)
  {
    return key.Aggregate((p, v) => 31*p + v.GetHashCode());
  }
}


此实现更好的原因有三个:


更具可读性-每个方法都是一行,或多或少是不言自明的(假设您熟悉计算多部分键的哈希码)
效率更高-此代码避免构建在散列密钥的过程中会反复丢弃的字符串
它提高了正确性-即使TKey字符串包含下划线,此实现也可以正常工作。


该实现使用LINQ方法SequenceEqualAggregate来缩短EqualsGetHashCode的代码。

关于c# - 如何从值类型T的List <List <T >>中删除重复项?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/22408543/

10-09 01:39