您是否有理由不只是使用数组?int[]
会表现更好。另外我假设列表包含重复项,否则您只会使用集合而没有问题。
一旦将它们添加到HashSet
. 归根结底,您将不得不使用依赖于SequenceEqual
. 但是您不必每次都这样做。相反,或者进行指数级的序列比较(例如——随着哈希集的增长,SequenceEqual
对每个现有成员进行一次)——如果你预先创建了一个好的哈希码,你可能需要做很少的这样的比较。虽然生成良好哈希码的开销可能与执行 a 的开销大致相同,但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
}
}
如果列表一旦添加就不会改变,这应该非常快。即使在列表可能经常更改的情况下,创建新哈希码的时间也可能与进行序列比较的时间差别不大(如果甚至更大)。