Есть ли причина, по которой вы не просто используете массив? 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
}
}
Если списки не будут меняться после добавления, это должно быть очень быстро. Даже в ситуациях, когда списки могут часто меняться, время создания нового хеш-кода, скорее всего, не сильно отличается (если вообще больше), чем время сравнения последовательностей.
person
Jamie Treworgy
schedule
01.04.2011
HashSet<List<int>>
кажется маловероятным инструментом для использования. - person marcind   schedule 02.04.2011using System.Collections.Generic
, и я не могу использовать List, он кричит на меня за использование HashSet... - person kralco626   schedule 07.04.2011