如何检查HashSet <List <int >>在C#中是否包含List <int>的重复值?

时间:2019-11-09 16:53:48

标签: c# list duplicates hashset

我在C#中确实有一个HashSet,如下所示:

HashSet<List<int>> _hash = new HashSet<List<int>>();

现在,我在其中插入了一个值,如下所示:

_hash.add(new List<int> {1,7});

当我在上面的代码之后编写以下代码时:

_hash.contains(new List<int>{1,7});

我期望它返回true,因为刚刚添加了相同的值,但是它确实返回了false。这确实使我感到困惑。此外,如何确保当我具有List的哈希集时,在向其中添加任何新值之前,其中没有重复项。

我认为使用HashSet的全部原因是为了避免任何重复,但似乎这允许重复。

现在,从角度看,我想要的只是当我有一个List>时,如何确保进入List>的每个元素(列表)都是唯一的?

2 个答案:

答案 0 :(得分:1)

您可以创建自己的类似只读集合。

public class ComparableReadOnlyCollection<T> : ReadOnlyCollection<T>
{
    public ComparableReadOnlyCollection(IList<T> list)
        : base(list.ToArray())
    {
    }

    public override bool Equals(object other)
    {
        return
            other is IEnumerable<T> otherEnumerable &&
            otherEnumerable.SequenceEqual(this);
    }

    public override int GetHashCode()
    {
        int hash = 43;
        unchecked {
            foreach (T item in this) {
                hash = 19 * hash + item.GetHashCode();
            }
        }
        return hash;
    }
}

请注意,ReadOnlyCollection<T>只是原始列表的包装。如果您修改此列表,则ReadOnlyCollection<T>将反映这些更改。我的实现将原始列表复制到一个数组中,以使其真正不可变。

但是请注意,如果元素T是引用类型,您仍然可以修改原始对象的成员!所以要小心

此测试按预期进行:

var hashSet = new HashSet<ComparableReadOnlyCollection<int>>();
hashSet.Add(new ComparableReadOnlyCollection<int>(new [] { 1, 7 }));

Console.WriteLine(hashSet.Contains(new ComparableReadOnlyCollection<int>(new [] { 1, 7 })));
Console.WriteLine(hashSet.Contains(new ComparableReadOnlyCollection<int>(new [] { 7, 1 })));
Console.WriteLine(hashSet.Contains(new ComparableReadOnlyCollection<int>(new [] { 1, 7, 0 })));

hashSet.Add(new ComparableReadOnlyCollection<int>(new [] { 1, 7 }));
hashSet.Add(new ComparableReadOnlyCollection<int>(new [] { 1, 7, 0 }));
hashSet.Add(new ComparableReadOnlyCollection<int>(new [] { 7, 1 }));
Console.WriteLine(hashSet.Count);
Console.ReadKey();

它打印

True
False
False
3

请注意,它不会打印4,因为该集中不能有重复项。


第二种解决方法:

阅读您的编辑后,我不确定您真正想要的是什么。您是要创建HashSet<int>而不是HashSet<List<int>>并比较列表的元素而不是列表本身吗?

HashSet<int> _hash = new HashSet<int>(new List<int> { 1, 1, 2, 3, 5, 8, 13 });    

现在,哈希集包含数字{1,2,3,5,8,13}。设置元素始终是唯一的。

然后您可以测试

var hash2 = new HashSet<int> { 3, 8 };

if (_hash.IsSupersetOf(hash2)) {
    Console.WriteLine("_hash contains 3 and 8");
}

或等价的内容:

if (hash2.IsSubsetOf(_hash)) {
    Console.WriteLine("_hash contains 3 and 8");
}

第三个解决方案:

List<HashSet<int>>呢?因为现在,您可以将set操作应用于列表的每个元素(哈希集)。

答案 1 :(得分:-1)

问题

在HashSet中添加列表时,您会添加一个新引用,因此从HashSet的角度来看,没有重复项。

Contains方法仅比较引用,因此在您的示例中有两个不同的引用。

您需要检查自己是否包含类似的列表。

使用扩展方法

using System.Collections.Generic;

static public class HashSetHelper
{
  static public bool ContainsSequence(this HashSet<List<int>> set, List<int> list)
  {
    if ( set == null || set.Count == 0 )
      return false;
    if ( list == null )
      return set.Contains(null);
    foreach ( var item in set )
    {
      if ( item.Count != list.Count )
        return false;
      for ( int index = 0; index < item.Count; index++ )
        if ( item[index] != list[index] )
          return false;
    }
    return true;
  }
}

假设{ 1, 7 }{ 7, 1 }不同,否则您需要更新算法。

您可以调整list为null的情况以返回true或false。

Fiddle Snippet

测试

HashSet<List<int>> _hash = new HashSet<List<int>>();

_hash.Add(new List<int> { 1, 7 });

Console.WriteLine(_hash.ContainsSequence(new List<int> { 1, 7 }));
Console.WriteLine(_hash.ContainsSequence(new List<int> { 7, 1 }));
Console.WriteLine(_hash.ContainsSequence(new List<int> { 1, 7, 5 }));
Console.WriteLine(_hash.ContainsSequence(new List<int> { 1 }));
Console.WriteLine(_hash.ContainsSequence(new List<int>()));
Console.WriteLine();

_hash.Clear();
Console.WriteLine(_hash.ContainsSequence(new List<int> { 1, 7 }));
Console.WriteLine(_hash.ContainsSequence(new List<int>()));
Console.WriteLine();

_hash.Add(new List<int>());
Console.WriteLine(_hash.ContainsSequence(new List<int>()));
Console.WriteLine(_hash.ContainsSequence(null));
Console.WriteLine(HashSetHelper.ContainsSequence(null, null));
Console.WriteLine();

_hash.Add(null);
Console.WriteLine(_hash.ContainsSequence(null));

输出

True
False
False
False
False

False
False

True
False
False

True

注意事项

您可以使用List<List<int>>HashSet<HastSet<int>>代替HashSet<List<int>>

但是请记住,HashSet不允许重复。

HashSet快速稳定。

HashSet vs. List performance