Я пытаюсь создать таблицу поиска в словаре на С #. Мне нужно преобразовать 3 кортежа значений в одну строку. Я пробовал использовать массивы в качестве ключей, но это не сработало, и я не знаю, что еще делать. На данный момент я подумываю о создании Словаря словарей или словарей, но это, вероятно, было бы не очень красиво, хотя я бы сделал это в javascript именно так.
c#
dictionary
hashtable
tuples
AlexH
источник
источник
GetHashCode
реализация не очень хороша. Он инвариантен относительно перестановки полей.new object()
равняться другомуnew object()
? Он не просто использует прямое сравнение ... попробуйте:bool test = new Tuple<int, string>(1, "foo").Equals(new Tuple<int, string>(1, "Foo".ToLower()));
Между подходами на основе кортежей и вложенных словарей почти всегда лучше использовать кортежи.
С точки зрения ремонтопригодности ,
гораздо проще реализовать функциональность, которая выглядит так:
чем
со стороны вызываемого абонента. Во втором случае каждое добавление, поиск, удаление и т. Д. Требует действий более чем с одним словарем.
Кроме того, если для вашего составного ключа в будущем потребуется еще одно (или меньше) поля, вам нужно будет значительно изменить код во втором случае (вложенный словарь), поскольку вам придется добавлять дополнительные вложенные словари и последующие проверки.
С точки зрения производительности лучший вывод, к которому вы можете прийти, - это измерить ее самостоятельно. Но есть несколько теоретических ограничений, которые вы можете учесть заранее:
В случае вложенного словаря наличие дополнительного словаря для каждого ключа (внешнего и внутреннего) будет иметь некоторые накладные расходы на память (больше, чем при создании кортежа).
В случае вложенного словаря все основные действия, такие как добавление, обновление, поиск, удаление и т. Д., Необходимо выполнять в двух словарях. Теперь есть случай, когда подход с использованием вложенного словаря может быть быстрее, то есть, когда просматриваемые данные отсутствуют, поскольку промежуточные словари могут обойти вычисление и сравнение полного хэш-кода, но опять же, это должно быть синхронизировано, чтобы быть уверенным. При наличии данных это должно быть медленнее, так как поиск должен выполняться дважды (или трижды в зависимости от вложенности).
Что касается кортежей подхода, .NET кортежи не самый производительный , когда они предназначены для использования в качестве ключей в наборах , так как его
Equals
иGetHashCode
реализации причин бокс для типов значений .Я бы выбрал словарь на основе кортежей, но если мне нужна более высокая производительность, я бы использовал свой собственный кортеж с лучшей реализацией.
Кстати, немного косметики могут сделать словарь крутым:
Вызовы в стиле индексатора могут быть намного чище и интуитивно понятны. Например,
Так что выставьте необходимые индексаторы в своем классе словаря, который внутренне обрабатывает вставки и поиск.
Кроме того, реализуйте подходящий
IEnumerable
интерфейс и предоставьтеAdd(TypeA, TypeB, TypeC, string)
метод, который предоставит вам синтаксис инициализатора коллекции, например:источник
string foo = dict[a][b][c]
:?a
. Вы можете просто перебирать любой словарь, как и любую обычную коллекцию, и проверять ключевое свойство, если оно естьa
. Если вы всегда хотите получить элемент в dict по первому свойству, тогда вы можете лучше разработать словарь как словарь словарей, как показано в моем ответе и запросеdict[a]
, что дает вам еще один словарь.4
для обоих ключейa
иb
, вы можете сделать его стандартным словарем и добавить такие значения, какdict[a] = 4
иdict[b] = 4
. Это может не иметь смысла, если по логике вашa
иb
должен быть одной единицей. В таком случае вы можете определить обычай,IEqualityComparer
который приравнивает два ключевых объекта как равные, если какие-либо из их свойств равны. Все это в общем можно сделать с помощью refelction.Если вы используете C # 7, вам следует рассмотреть возможность использования кортежей значений в качестве составного ключа. Кортежи значений обычно обеспечивают лучшую производительность, чем традиционные ссылочные кортежи (
Tuple<T1, …>
), поскольку кортежи значений являются типами значений (структурами), а не ссылочными типами, поэтому они позволяют избежать затрат на выделение памяти и сборку мусора. Кроме того, они предлагают более лаконичный и интуитивно понятный синтаксис, позволяющий при желании именовать их поля. Они также реализуютIEquatable<T>
интерфейс, необходимый для словаря.источник
Хорошие, чистые, быстрые, простые и понятные способы:
добавьте что-то подобное:
Таким образом, вы можете использовать его со словарем:
источник
public TypeA DataA => Item1;
Если по какой-то причине вы действительно хотите избежать создания собственного класса Tuple или использования встроенного в .NET 4.0 класса, есть еще один возможный подход; вы можете объединить три ключевых значения в одно значение.
Например, если три значения представляют собой целые типы вместе, не занимающие более 64 бит, вы можете объединить их в файл
ulong
.В худшем случае вы всегда можете использовать строку, если убедитесь, что три компонента в ней разделены некоторым символом или последовательностью, которая не встречается внутри компонентов ключа, например, тремя числами, которые вы можете попробовать:
Очевидно, что в этом подходе есть некоторые накладные расходы на композицию, но в зависимости от того, для чего вы его используете, это может быть достаточно тривиальным, чтобы не заботиться об этом.
источник
JavaScriptSerializer
для объединения для вас массива строковых и / или целочисленных типов. Таким образом, вам не нужно самостоятельно придумывать символ-разделитель.key1
,key2
,key3
) были строки , содержащие deliminator ("#"
)Я бы переопределил ваш кортеж с помощью правильного GetHashCode и просто использовал его как ключ.
Пока вы перегружаете правильные методы, вы должны видеть приличную производительность.
источник
Вот кортеж .NET для справки:
источник
Если ваш код потребления может обойтись интерфейсом IDictionary <> вместо Dictionary, я бы инстинктивно использовал SortedDictionary <> с настраиваемым компаратором массивов, то есть:
И создайте таким образом (используя int [] только для конкретного примера):
источник