Есть ли причина, по которой вы не просто используете массив?int[]
будет работать лучше.Также я предполагаю, что списки содержат дубликаты, в противном случае вы просто использовали бы наборы и не имели бы проблемы.
Похоже, что их содержимое не изменится (сильно) после добавления в HashSet
.В конце дня вам придется использовать компаратор, который возвращается к SequenceEqual
.Но вам не нужно делать это каждый раз.Вместо этого или выполняйте экспоненциальное число сравнений последовательностей (например, - по мере роста хэш-набора, делая SequenceEqual
для каждого существующего члена) - если вы заранее создаете хороший хеш-код, вам может потребоваться сделать очень мало таких сравнений.Хотя затраты на генерацию хорошего хэш-кода, вероятно, примерно такие же, как при выполнении SequenceEqual
, вы делаете это только один раз для каждого списка.
Итак, при первой работе с конкретным List<int>
, вы должны генерировать хеш на основе упорядоченной последовательности чисел и кэшировать его.Затем при следующем сравнении списка можно использовать кэшированное значение.Я не уверен, как вы могли бы сделать это с помощью компаратора в верхней части моей головы (может быть, статический словарь?) - но вы могли бы реализовать List
оболочку, которая делает это легко.
Вот основныеидея.Вы должны быть осторожны, чтобы убедиться, что он не хрупкий (например, убедитесь, что вы теряете любой кэшированный хеш-код при изменении членов), но это не похоже на типичную ситуацию для вашего использования.this.
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
}
}
Если списки не изменятся после добавления, это должно быть очень быстро.Даже в ситуациях, когда списки могут часто меняться, время создания нового хеш-кода, скорее всего, не сильно отличается (если вообще больше) от сравнения последовательностей.