Обратный поиск во вложенном словаре
Dictionary<string, Dictionary<string, ... >...> nestedDictionary;
Выше Dictionary
имеет one-to-many
отношения на каждом уровне сверху вниз. Добавить элемент довольно легко, так как у нас есть листовой объект, и мы начинаем снизу, создавая словари и добавляя каждый к соответствующему родителю...
Моя проблема в том, когда я хочу найти предмет во внутренних словарях. Есть два варианта:
- Вложенные
foreach
и найдите элемент, сделайте снимок всех циклов в тот момент, когда мы нашли элемент, и выйдите из всех циклов. Тогда мы знаем, что родословная элемента - string1->string2->...->stringN. Проблемы с этим решением: A) Производительность B) Потоковая безопасность (поскольку я хочу удалить элемент, родитель, если у него нет дочернего элемента, и его родитель, если у него нет дочернего элемента...) - Создание обратного просмотра словаря и индексация добавленных элементов. Что-то вроде
Tuple
для всех внешних словарей. Затем добавьте элемент в качестве ключа и все внешние родители какTuple
члены. Проблема: A) Резервирование B) Сохранение синхронизированного обратного просмотраDictionary
с основнымDictionary
,
Есть идеи для быстрого и многопоточного решения?
2 ответа
Хотя у меня мало опыта работы с библиотекой коллекций C5, похоже, вы могли бы использовать их класс TreeDictionary. Он поставляется с целым набором полезных методов для поиска, итерации и изменения дерева, и на удивление хорошо документирован.
Другой вариант - использовать библиотеку QuickGraph (которую вы можете найти в NuGet или в codeplex). Это включает в себя некоторые знания теории графов, но в остальном очень полезная библиотека.
Обе библиотеки требуют, чтобы вы обрабатывали параллелизм, как и стандартные коллекции BCL.
Похоже, у вас на самом деле есть более двух уровней Dictionary
, Поскольку вы не можете поддерживать переменное количество словарей, используя синтаксис этого типа:
Dictionary<string, Dictionary<string, ... >...> nestedDictionary;
Я могу только предположить, что это число больше двух. Допустим, это три. Для любой структуры данных, которую вы строите, у вас есть предполагаемое использование и операции, которые вы хотите эффективно выполнять.
Я собираюсь предположить, что вам нужны такие звонки:
var dictionary = new ThreeLevelDictionary();
dictionary.Add(string1, string2, string3, value);
var value = dictionary[string1, string2, string3];
dictionary.Remove(string1, string2, string3);
И (критически важный для вопроса) обратный поиск, который вы описываете:
var strings = dictionary.FindKeys(value);
Если это операции, которые вам нужно выполнить и выполнить быстро, то одна структура данных, которую вы можете использовать, это Dictionary
с Tuple
ключ:
public class ThreeLevelDictionary<TValue> : Dictionary<Tuple<string, string, string>, TValue>
{
public void Add(string s1, string s2, string s3, TValue value)
{
Add(Tuple.Create(s1, s2, s3), value);
}
public TValue this[string s1, string s2, string s3]
{
get { return this[Tuple.Create(s1, s2, s3)]; }
set { value = this[Tuple.Create(s1, s2, s3)]; }
}
public void Remove(string s1, string s2, string s3)
{
Remove(Tuple.Create(s1, s2, s3);
}
public IEnumerable<string> FindKeys(TValue value)
{
foreach (var key in Keys)
{
if (EqualityComparer<TValue>.Default.Equals(this[key], value))
return new string[] { key.Item1, key.Item2, key.Item3 };
}
throw new InvalidOperationException("missing value");
}
}
Теперь вы можете создать хеш - таблицу обратного просмотра, используя другую Dictionary
если производительность показывает, что это узкое место.
Если предыдущие любимые операции не являются теми, которые вы хотите выполнить, то эта структура данных может не соответствовать вашим потребностям. В любом случае, если вы сначала опишете интерфейс, в котором кратко излагается, что вы хотите, чтобы структура данных выполняла, тогда легче увидеть, есть ли другие альтернативы.