Какова наилучшая структура данных в .NET для поиска по строковому ключу или числовому индексу?

Я ищу наиболее идеальную структуру данных (по производительности и простоте использования), из которой можно получить значения по строковому ключу или индексу. Словарь не работает, потому что вы не можете получить по индексу. Любые идеи?


person JC Grubbs    schedule 26.09.2008    source источник


Ответы (7)


Вам нужен класс OrderedDictionary. Вам нужно будет включить пространство имен System.Collections.Specialized:

    OrderedDictionary od = new OrderedDictionary(); 
    od.Add("abc", 1); 
    od.Add("def", 2); 
    od.Add("ghi", 3); 
    od.Add("jkl", 4); 

    // Can access via index or key value:      
    Console.WriteLine(od[1]);       
    Console.WriteLine(od["def"]);
person Mitch Wheat    schedule 26.09.2008
comment
Это не общее. Пожалуйста, проверьте общие классы SortedList или SortedDictionary для лучшей производительности. - person Ben Hoffstein; 26.09.2008
comment
OrderedDictionary соответствует всем требованиям, изложенным в вопросе, если производительность адекватна, а это можно определить только после реализации. - person Jeffrey L Whitledge; 26.09.2008
comment
Хорошо, но трудно представить, почему кто-то предпочел бы это универсальному варианту, если бы они не использовали .NET 1.0 или .NET 1.1. - person Ben Hoffstein; 26.09.2008
comment
Хорошая находка, похоже, это единственная коллекция ключей/значений, которая сохраняет свой индекс. - person FlySwat; 26.09.2008

Существует System.Collections.ObjectModel.KeyedCollection‹ string,TItem>, производная от Collection‹ TItem>. Получение — O(1).

class IndexableDictionary<TItem> : KeyedCollection<string, TItem>
 { Dictionary<TItem, string> keys = new Dictionary<TItem, string>();

   protected override string GetKeyForItem(TItem item) { return keys[item];}

   public void Add(string key, TItem item) 
    { keys[item] = key;
      this.Add(item);
    }
 }
person Mark Cidade    schedule 26.09.2008
comment
KeyedCollection — это абстрактный класс, ему пришлось бы реализовать коллекцию Key/Value поверх него. - person FlySwat; 26.09.2008
comment
Вам нужно только реализовать GetKeyForItem() для KeyedCollection - person Mark Cidade; 26.09.2008
comment
Использование KeyedCollection почти наверняка является лучшим выбором, если объект содержит свой ключ, потому что вы инкапсулируете логику извлечения ключа в одной функции, а не везде, где используется коллекция. - person Greg Beech; 26.09.2008

Одно слово предупреждения. OrderedDictionary имеет действительно плохие характеристики производительности для большинства операций, кроме вставки и поиска: как для удаления, так и для изменения значения может потребоваться линейный поиск по всему списку, что приводит к времени выполнения O (н). (Для модификации это зависит от того, был ли доступ осуществлен по индексу или по ключу.)

Для большинства операций с разумными объемами данных это совершенно неприемлемо. Кроме того, структура данных хранит элементы как в линейном векторе, так и в хеш-таблице, что приводит к некоторым накладным расходам памяти.

Если поиск по индексу не происходит слишком часто, SortedList или SortedDictionary будут иметь гораздо лучшие характеристики производительности (доступ по индексу можно получить с помощью метода расширения ElementAt).

Если, с другой стороны, доступ по индексу является нормой, тогда вообще прекратите использовать структуры данных словаря и просто храните свои значения в List<KeyValuePair<TKey, TValue>>. Хотя это означает линейный поиск доступа по ключу, все остальные операции очень дешевы, а общую производительность на практике трудно превзойти.

/EDIT: Конечно, последний также является структурой данных словаря в теоретическом смысле. Вы даже можете инкапсулировать его в класс, реализующий соответствующий интерфейс.

person Konrad Rudolph    schedule 26.09.2008
comment
Какой смысл иметь индекс, если ему нужно время поиска O (N), чтобы добраться до него? - person FlySwat; 26.09.2008
comment
System.Collections.ObjectModel.KeyedCollection использует словарь‹T› - person Mark Cidade; 28.09.2008

Коллекции на основе хеша (Dictionary, Hashtable, HashSet) отсутствуют, потому что у вас не будет индекса, поскольку вам нужен индекс, я бы использовал вложенный универсальный:

List<KeyValuePair<K,V>>

Конечно, вы теряете поиск ключа O (1), который вы получаете с хешами.

person FlySwat    schedule 26.09.2008
comment
Это ужасно. Список дает вам O (n) поиск, тогда как SortedList или SortedDictionary дают вам O (log n). - person Ben Hoffstein; 26.09.2008
comment
SortedList также означает, что индекс бесполезен. Кроме того, GetByIndex выполняет поиск O(N). - person FlySwat; 26.09.2008

Словарь может работать с linq. Хотя я не знаю о возможных проблемах с производительностью. Словарь.ЭлементАт(индекс);

person mattlant    schedule 26.09.2008
comment
ПОСЛЕ размышлений об этом, это может быть плохо, так как я думаю, что ему нужно будет перечислить этот индекс. - person mattlant; 26.09.2008

Я рекомендую использовать SortedDictionary‹string, TValue› или SortedList‹string, TValue›. Оба имеют производительность поиска O(log n).

Различия приведены в библиотеке MSDN:

SortedList‹(Of ‹(TKey, TValue>)>) использует меньше памяти, чем SortedDictionary‹(Of ‹(TKey, TValue>)>).

SortedDictionary‹(Of ‹(TKey, TValue>)>) имеет более быстрые операции вставки и удаления для несортированных данных: O(log n) по сравнению с O(n) для SortedList‹(Of ‹(TKey, TValue>)>).

Если список заполняется сразу всеми отсортированными данными, SortedList‹(Of ‹(TKey, TValue>)>) работает быстрее, чем SortedDictionary‹(Of ‹(TKey, TValue>)>).

По моему опыту, SortedDictionary более подходит для большинства типичных бизнес-сценариев, поскольку данные обычно изначально не сортируются при использовании подобных структур, а накладные расходы памяти SortedDictionary редко бывают критическими. Но если для вас важна производительность, я предлагаю вам реализовать оба варианта и провести измерения.

person Magnus Akselvoll    schedule 26.09.2008
comment
Вы не можете доверять тому, чтобы индекс оставался постоянным в sortedList или sortedDictionary. Что хорошего в индексе, который может измениться в середине операции с данными? - person FlySwat; 26.09.2008

Вы ищете что-то вроде класса SortedList. (а также общая версия).

person Ben Hoffstein    schedule 26.09.2008
comment
Числового индексатора нет, поэтому вам придется использовать list.Values[i] - person Mark Cidade; 26.09.2008
comment
Или вы можете просто использовать метод GetByIndex(). - person Ben Hoffstein; 26.09.2008
comment
Верно. Я смотрел универсальную версию. - person Mark Cidade; 26.09.2008
comment
SortedList не сохраняет исходный порядок элементов, он сортирует их в порядке ключа. Это не похоже на семантику, которую ищет оригинальный постер, хотя я могу ошибаться, поскольку вопрос в этом отношении несколько неоднозначен. - person Greg Beech; 26.09.2008
comment
Он попросил что-то, к чему можно получить доступ по ключу или по индексу. О заказе речи не шло. Я действительно удивлен некоторыми ответами на этот вопрос. - person Ben Hoffstein; 26.09.2008
comment
GetByIndex равен O(N), и индекс бесполезен, так как ему нельзя доверять. Я могу гарантировать, что причина, по которой он хочет получить доступ к индексу, также означает, что индекс не должен изменяться случайным образом. - person FlySwat; 26.09.2008