У меня есть некоторые объекты в Списке, скажем, List<MyClass>
и MyClass имеет несколько свойств. Я хотел бы создать индекс списка на основе 3 свойств MyClass. В этом случае 2 из свойств являются интервалом, и одно свойство является датой и временем.
В основном я хотел бы смочь сделать что-то как:
Dictionary< CompositeKey , MyClass > MyClassListIndex = Dictionary< CompositeKey , MyClass >();
//Populate dictionary with items from the List<MyClass> MyClassList
MyClass aMyClass = Dicitonary[(keyTripletHere)];
Я иногда создаю несколько словарей по списку для индексации различных свойств классов, которые он содержит. Я не уверен, как лучше всего обработать составные ключи все же. Я рассмотрел выполнение контрольной суммы трех значений, но это рискует коллизиями.
Вы можете хранить их в структуре и использовать ее в качестве ключа:
struct CompositeKey
{
public int value1;
public int value2;
public DateTime value3;
}
Ссылка для получения хэш-кода: http://msdn.microsoft.com/en-us/library/system.valuetype.gethashcode.aspx
На ум сразу приходят два подхода:
Сделайте, как предложил Кевин, и напишите структуру, которая будет служить вашим ключом. Убедитесь, что эта структура реализует IEquatable
и переопределите ее методы Equals
и GetHashCode
.
Напишите класс, который использует вложенные словари внутри. Что-то вроде: TripleKeyDictionary
... Этот класс будет иметь внутренний член типа Dictionary
, и будет раскрывать такие методы, как this[TKey1 k1, TKey2 k2, TKey3 k3]
, ContainsKeys(TKey1 k1, TKey2 k2, TKey3 k3)
, и т.д.
* Несколько слов о необходимости переопределения метода Equals
: хотя верно, что метод Equals
для struct по умолчанию сравнивает значение каждого члена, он делает это с помощью отражения - что неизбежно влечет за собой затраты производительности - и поэтому не является не очень подходящей реализацией для того, что предназначено для использования в качестве ключа в словаре (по моему мнению, во всяком случае). Согласно документации MSDN по ValueType.Equals
:
Реализация по умолчанию метода Equals использует отражение для сравнения соответствующих полей obj и данного экземпляра. Переопределите Equals для определенного типа, чтобы улучшить производительность метода и более точно отразить концепцию равенства для данного типа.
Как насчет Dictionary
?
Это позволит вам сделать:
MyClass item = MyData[8][23923][date];
Лучший способ, который я мог придумать, - это создать структуру CompositeKey и убедитесь, что переопределяют методы GetHashCode () и Equals (), чтобы обеспечить скорость и точность при работе с коллекцией:
class Program
{
static void Main(string[] args)
{
DateTime firstTimestamp = DateTime.Now;
DateTime secondTimestamp = firstTimestamp.AddDays(1);
/* begin composite key dictionary populate */
Dictionary<CompositeKey, string> compositeKeyDictionary = new Dictionary<CompositeKey, string>();
CompositeKey compositeKey1 = new CompositeKey();
compositeKey1.Int1 = 11;
compositeKey1.Int2 = 304;
compositeKey1.DateTime = firstTimestamp;
compositeKeyDictionary[compositeKey1] = "FirstObject";
CompositeKey compositeKey2 = new CompositeKey();
compositeKey2.Int1 = 12;
compositeKey2.Int2 = 9852;
compositeKey2.DateTime = secondTimestamp;
compositeKeyDictionary[compositeKey2] = "SecondObject";
/* end composite key dictionary populate */
/* begin composite key dictionary lookup */
CompositeKey compositeKeyLookup1 = new CompositeKey();
compositeKeyLookup1.Int1 = 11;
compositeKeyLookup1.Int2 = 304;
compositeKeyLookup1.DateTime = firstTimestamp;
Console.Out.WriteLine(compositeKeyDictionary[compositeKeyLookup1]);
CompositeKey compositeKeyLookup2 = new CompositeKey();
compositeKeyLookup2.Int1 = 12;
compositeKeyLookup2.Int2 = 9852;
compositeKeyLookup2.DateTime = secondTimestamp;
Console.Out.WriteLine(compositeKeyDictionary[compositeKeyLookup2]);
/* end composite key dictionary lookup */
}
struct CompositeKey
{
public int Int1 { get; set; }
public int Int2 { get; set; }
public DateTime DateTime { get; set; }
public override int GetHashCode()
{
return Int1.GetHashCode() ^ Int2.GetHashCode() ^ DateTime.GetHashCode();
}
public override bool Equals(object obj)
{
if (obj is CompositeKey)
{
CompositeKey compositeKey = (CompositeKey)obj;
return ((this.Int1 == compositeKey.Int1) &&
(this.Int2 == compositeKey.Int2) &&
(this.DateTime == compositeKey.DateTime));
}
return false;
}
}
}
Статья MSDN о GetHashCode ():
http: // msdn .microsoft.com / en-us / library / system.object.gethashcode.aspx
Другим решением для уже упомянутых было бы хранение какого-то списка всех сгенерированных ключей, и когда новый объект генерируется, вы генерируете его хэш-код (просто в качестве отправной точки), проверяйте, есть ли он уже в списке. , если это так, добавьте к нему какое-то случайное значение и т. д., пока не получите уникальный ключ, затем сохраните этот ключ в самом объекте и в списке и всегда возвращайте его как ключ.