如何创建HashSet< List< Int>>有不同的元素?

我有一个包含多个整数列表的HashSet - 即
HashSet<List<int>>
为了保持独特性,我目前要做两件事: 1.手动循环现有列表,使用
SequenceEquals
查找重复项。 2.对各个列表进行排序,使
SequenceEquals
当前正常工作。 有一个更好的方法吗?是否存在我可以提供给HashSet的现有IEqualityComparer,以便
HashSet.Add()
可以自动处理唯一性?
var hashSet = new HashSet<List<int>>();

for(/* some condition */)
{
    List<int> list = new List<int>();

    ...

    /* for eliminating duplicate lists */

    list.Sort();

    foreach(var set in hashSet)
    {
        if (list.SequenceEqual(set))
        {
            validPartition = false;
            break;
        }
    }

    if (validPartition)
           newHashSet.Add(list);
}
谢谢 !     
已邀请:
这是一个可能的比较器,用于比较
IEnumerable<T>
的元素。您仍需要在添加之前手动排序。 人们可以在比较器中建立排序,但我不认为这是明智的选择。添加列表的规范形式似乎更明智。 此代码仅适用于.net 4,因为它利用了泛型差异。如果您需要早期版本,则需要将
IEnumerable
替换为
List
,或者为集合类型添加第二个通用参数。
class SequenceComparer<T>:IEqualityComparer<IEnumerable<T>>
{
    public bool Equals(IEnumerable<T> seq1,IEnumerable<T> seq2)
    {
        return seq1.SequenceEqual(seq2);
    }

    public int GetHashCode(IEnumerable<T> seq)
    {
        int hash=1234567;
        foreach(T elem in seq)
            hash=hash*37+elem.GetHashCode();
        return hash;
    }
}

void Main()
{
    var hashSet = new HashSet<List<int>>(new SequenceComparer<int>());

    List<int> test=new int[]{1,3,2}.ToList();
    test.Sort();
    hashSet.Add(test);

    List<int> test2=new int[]{3,2,1}.ToList();
    test2.Sort();       
    hashSet.Contains(test2).Dump();
}
    
这开始是错误的,它必须是
HashSet<ReadOnlyCollection<>>
,因为你不能允许列表更改并使set谓词无效。然后,这允许您在将集合添加到集合时计算O(n)中的哈希码。并且进行O(n)测试以检查它是否已经在具有非常罕见的O(n ^ 2)最坏情况的集合中,如果所有哈希值都相等。将计算的哈希存储在集合中。     
您是不是只使用阵列?
int[]
会表现得更好。另外我假设列表包含重复项,否则你只是使用集合而没有问题。 一旦它们被添加到
HashSet
,它们的内容似乎不会(很多)改变。在一天结束时,你将不得不使用一个落在
SequenceEqual
的比较器。但是你不必每次都这样做。相反或做一个指数的序列比较(例如 - 随着哈希集增长,对每个现有成员做一个
SequenceEqual
) - 如果你预先创建一个好的哈希码,你可能不得不做很少这样的比较。虽然生成一个好的哈希码的开销可能和做
SequenceEqual
的开销差不多,但你只需要为每个列表做一次。 因此,当您第一次操作特定的
List<int>
时,您应该根据有序的数字序列生成一个哈希并缓存它。然后,下次比较列表时,可以使用缓存的值。我不知道你怎么能用我的头顶上的比较器(也许是一个静态字典?)来做到这一点 - 但你可以实现
List
包装器,这很容易做到这一点。 这是一个基本的想法。您需要小心确保它不易碎(例如,确保在成员更改时使任何缓存的哈希代码无效)但看起来这似乎不是您使用方式的典型情况这个。
public class FasterComparingList<T>: IList<T>, IList, ... 
    /// whatever you need to implement
{
   // Implement your interfaces against InnerList
   // Any methods that change members of the list need to
   // set _LongHash=null to force it to be regenerated
   public List<T> InnerList { ... lazy load a List }
   public int GetHashCode()
   {
       if (_LongHash==null) {
           _LongHash=GetLongHash();
       }
       return (int)_LongHash;
   }
   private int? _LongHash=null;
   public bool Equals(FasterComparingList<T> list)
   {
       if (InnerList.Count==list.Count) {
           return true;
       }
       // you could also cache the sorted state and skip this if a list hasn't
       // changed since the last sort
       // not sure if native `List` does
       list.Sort();
       InnerList.Sort();
       return InnerList.SequenceEqual(list);
   }
   protected int GetLongHash()
   {
       return .....
       // something to create a reasonably good hash code -- which depends on the 
       // data. Adding all the numbers is probably fine, even if it fails a couple 
       // percent of the time you're still orders of magnitude ahead of sequence
       // compare each time
   } 
}
如果列表一旦添加就不会改变,这应该非常快。即使在列表可能经常更改的情况下,创建新哈希码的时间也不可能与执行序列比较的情况完全不同(如果更大)。     
如果你没有指定IEQualityComparer,那么将使用默认类型,所以我认为你需要做的是创建你自己的IEQualityComparer实现,并将它传递给你的HashSet的构造函数。这是一个很好的例子。     

要回复问题请先登录注册