При использовании.NET 3.5 используйте Lookup
класс.
РЕДАКТИРОВАНИЕ: Вы обычно создаете Lookup
использование Enumerable.ToLookup
. Это предполагает, что Вы не должны изменять его впоследствии - но я обычно нахожу, что это достаточно хорошо.
, Если это не делает работа для Вас, я не думаю, что существует что-либо в платформе, которая поможет - и использование словаря так хорошо, как это добирается: (
Дублирующиеся ключи нарушают все условия контракта Словаря. В словаре каждый ключ уникален и отображается на единственном значении. Если Вы хотите связать объект с произвольным числом дополнительных объектов, лучший выбор мог бы быть чем-то сродни DataSet (говоря обычным языком таблица). Поместите свои ключи в одном столбце и свои значения в другом. Это значительно медленнее, чем словарь, но это - Ваш компромисс для потери способности хешировать ключевые объекты.
Вы имеете в виду конгруэнтный и не фактический дубликат? Иначе хеш-таблица не была бы в состоянии работать.
Конгруэнтный означает, что два отдельных ключа могут хешировать к эквивалентной стоимости, но ключи не равны.
, Например: скажите, что хеш-функция Вашей хеш-таблицы была просто hashval = ключевая модификация 3. И 1 и 4 карты к 1, но различные значения. Это - то, где Ваша идея списка играет роль.
, Когда Вам нужно к поиску 1, то значение хешируется к 1, список пересечен, пока Ключ = 1 не найден.
, Если бы Вы допускали, делают дубликаты ключа, которые будут вставлены, Вы не были бы в состоянии дифференцироваться, какие ключи отображаются на который значения.
Я думаю, что что-то как List<KeyValuePair<object, object>>
сделало бы Задание.
Очень важное примечание относительно использования Поиска:
можно создать экземпляр Lookup(TKey, TElement)
путем вызова ToLookup
на объекте, который реализует IEnumerable(T)
нет никакого общедоступного конструктора для создания нового экземпляра Lookup(TKey, TElement)
. Кроме того, Lookup(TKey, TElement)
объекты неизменны, то есть, Вы не можете добавить или удалить элементы или ключи от Lookup(TKey, TElement)
объект после того, как он был создан.
я думал бы, что это будет выставочным стопором для большей части использования.
Я просто столкнулся библиотека PowerCollections, которая включает, среди прочего, класс под названием MultiDictionary. Это аккуратно обертывает этот тип функциональности.
Если Вы используете строки и в качестве ключей и в качестве значений, можно использовать Система. Наборы. Специализированный. NameValueCollection, который возвратит массив строковых значений через GetValues (строковый ключ) метод.
NameValueCollection поддерживает несколько строковых значений под одним ключом (который является также строкой), но это - единственный пример, о котором я знаю.
я склонен создавать конструкции, подобные той в Вашем примере, когда я сталкиваюсь с ситуациями, где мне нужна такая функциональность.
Можно создать собственную обертку словаря, что-то вроде этого один, в качестве награды она поддерживает нулевое значение как ключ:
/// <summary>
/// Dictionary which supports duplicates and null entries
/// </summary>
/// <typeparam name="TKey">Type of key</typeparam>
/// <typeparam name="TValue">Type of items</typeparam>
public class OpenDictionary<TKey, TValue>
{
private readonly Lazy<List<TValue>> _nullStorage = new Lazy<List<TValue>>(
() => new List<TValue>());
private readonly Dictionary<TKey, List<TValue>> _innerDictionary =
new Dictionary<TKey, List<TValue>>();
/// <summary>
/// Get all entries
/// </summary>
public IEnumerable<TValue> Values =>
_innerDictionary.Values
.SelectMany(x => x)
.Concat(_nullStorage.Value);
/// <summary>
/// Add an item
/// </summary>
public OpenDictionary<TKey, TValue> Add(TKey key, TValue item)
{
if (ReferenceEquals(key, null))
_nullStorage.Value.Add(item);
else
{
if (!_innerDictionary.ContainsKey(key))
_innerDictionary.Add(key, new List<TValue>());
_innerDictionary[key].Add(item);
}
return this;
}
/// <summary>
/// Remove an entry by key
/// </summary>
public OpenDictionary<TKey, TValue> RemoveEntryByKey(TKey key, TValue entry)
{
if (ReferenceEquals(key, null))
{
int targetIdx = _nullStorage.Value.FindIndex(x => x.Equals(entry));
if (targetIdx < 0)
return this;
_nullStorage.Value.RemoveAt(targetIdx);
}
else
{
if (!_innerDictionary.ContainsKey(key))
return this;
List<TValue> targetChain = _innerDictionary[key];
if (targetChain.Count == 0)
return this;
int targetIdx = targetChain.FindIndex(x => x.Equals(entry));
if (targetIdx < 0)
return this;
targetChain.RemoveAt(targetIdx);
}
return this;
}
/// <summary>
/// Remove all entries by key
/// </summary>
public OpenDictionary<TKey, TValue> RemoveAllEntriesByKey(TKey key)
{
if (ReferenceEquals(key, null))
{
if (_nullStorage.IsValueCreated)
_nullStorage.Value.Clear();
}
else
{
if (_innerDictionary.ContainsKey(key))
_innerDictionary[key].Clear();
}
return this;
}
/// <summary>
/// Try get entries by key
/// </summary>
public bool TryGetEntries(TKey key, out IReadOnlyList<TValue> entries)
{
entries = null;
if (ReferenceEquals(key, null))
{
if (_nullStorage.IsValueCreated)
{
entries = _nullStorage.Value;
return true;
}
else return false;
}
else
{
if (_innerDictionary.ContainsKey(key))
{
entries = _innerDictionary[key];
return true;
}
else return false;
}
}
}
образец использования:
var dictionary = new OpenDictionary<string, int>();
dictionary.Add("1", 1);
// The next line won't throw an exception;
dictionary.Add("1", 2);
dictionary.TryGetEntries("1", out List<int> result);
// result is { 1, 2 }
dictionary.Add(null, 42);
dictionary.Add(null, 24);
dictionary.TryGetEntries(null, out List<int> result);
// result is { 42, 24 }
Класс List действительно работает вполне хорошо подходит для коллекций ключ / значение, содержащих дубликаты, в которых вы хотели бы перебирать коллекцию. Пример:
List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>();
// add some values to the collection here
for (int i = 0; i < list.Count; i++)
{
Print(list[i].Key, list[i].Value);
}
В ответ на исходный вопрос. Что-то вроде Dictionary
реализовано в классе под названием MultiMap
в The Code Project
.
Вы можете найти больше информации по следующей ссылке : http://www.codeproject.com/KB/cs/MultiKeyDictionary.aspx