Подтвердить что ты не робот

С# dictionary Как добавить несколько значений для одного ключа?

Я создал объект словаря

Dictionary<string, List<string>> dictionary =
    new Dictionary<string,List<string>>();

Я хочу добавить строковые значения в список строк для данного одного ключа. Если ключ еще не существует, я должен добавить новый ключ. List<string> не является предопределенным, я имею в виду, что я не создавал объект списка, а затем предоставлялся dictionary.Add("key",Listname). Как динамически создать этот объект списка в dictionary.Add("key",Listname), а затем добавить строки в этот список. Если мне нужно добавить 100 ключей, тогда мне нужно создать 100 списков, прежде чем выполнять инструкцию dictionary.Add, а также мне нужно проиндексировать содержимое этих списков?

Спасибо.

4b9b3361

Ответ 1

Обновление: проверяйте существование с помощью TryGetValue, чтобы выполнить только один поиск в случае, когда у вас есть список:

List<int> list;

if (!dictionary.TryGetValue("foo", out list))
{
    list = new List<int>();
    dictionary.Add("foo", list);
}

list.Add(2);

<ч/" > Оригинал: Проверьте наличие и добавьте один раз, затем введите в словарь, чтобы получить список и добавить в список как обычно:

var dictionary = new Dictionary<string, List<int>>();

if (!dictionary.ContainsKey("foo"))
    dictionary.Add("foo", new List<int>());

dictionary["foo"].Add(42);
dictionary["foo"].AddRange(oneHundredInts);

Или List<string>, как в вашем случае.

В стороне, если вы знаете, сколько элементов, которые вы собираетесь добавить в динамическую коллекцию, например List<T>, предпочитает конструктор, который берет начальную емкость списка: new List<int>(100);.

Это позволит захватить память, необходимую для удовлетворения заданной производительности, вместо того, чтобы захватывать небольшие куски каждый раз, когда она начинает заполняться. Вы можете сделать то же самое со словарями, если знаете, что у вас есть 100 ключей.

Ответ 2

Если я понял, чего вы хотите:

dictionary.Add("key", new List<string>()); 

позже...

dictionary["key"].Add("string to your list");

Ответ 3

Dictionary<string, List<string>> dictionary = new Dictionary<string,List<string>>();

foreach(string key in keys) {
    if(!dictionary.ContainsKey(key)) {
        //add
        dictionary.Add(key, new List<string>());
    }
    dictionary[key].Add("theString");
}

Если ключ не существует, добавляется новый List (внутри if). Иначе ключ существует, поэтому просто добавьте новое значение в List под этим ключом.

Ответ 4

Вы можете использовать мою реализацию multimap, которая происходит от Dictionary<K, List<V>>. Он не идеален, однако он неплохо работает.

/// <summary>
/// Represents a collection of keys and values.
/// Multiple values can have the same key.
/// </summary>
/// <typeparam name="TKey">Type of the keys.</typeparam>
/// <typeparam name="TValue">Type of the values.</typeparam>
public class MultiMap<TKey, TValue> : Dictionary<TKey, List<TValue>>
{

    public MultiMap()
        : base()
    {
    }

    public MultiMap(int capacity)
        : base(capacity)
    {
    }

    /// <summary>
    /// Adds an element with the specified key and value into the MultiMap. 
    /// </summary>
    /// <param name="key">The key of the element to add.</param>
    /// <param name="value">The value of the element to add.</param>
    public void Add(TKey key, TValue value)
    {
        List<TValue> valueList;

        if (TryGetValue(key, out valueList)) {
            valueList.Add(value);
        } else {
            valueList = new List<TValue>();
            valueList.Add(value);
            Add(key, valueList);
        }
    }

    /// <summary>
    /// Removes first occurence of an element with a specified key and value.
    /// </summary>
    /// <param name="key">The key of the element to remove.</param>
    /// <param name="value">The value of the element to remove.</param>
    /// <returns>true if the an element is removed;
    /// false if the key or the value were not found.</returns>
    public bool Remove(TKey key, TValue value)
    {
        List<TValue> valueList;

        if (TryGetValue(key, out valueList)) {
            if (valueList.Remove(value)) {
                if (valueList.Count == 0) {
                    Remove(key);
                }
                return true;
            }
        }
        return false;
    }

    /// <summary>
    /// Removes all occurences of elements with a specified key and value.
    /// </summary>
    /// <param name="key">The key of the elements to remove.</param>
    /// <param name="value">The value of the elements to remove.</param>
    /// <returns>Number of elements removed.</returns>
    public int RemoveAll(TKey key, TValue value)
    {
        List<TValue> valueList;
        int n = 0;

        if (TryGetValue(key, out valueList)) {
            while (valueList.Remove(value)) {
                n++;
            }
            if (valueList.Count == 0) {
                Remove(key);
            }
        }
        return n;
    }

    /// <summary>
    /// Gets the total number of values contained in the MultiMap.
    /// </summary>
    public int CountAll
    {
        get
        {
            int n = 0;

            foreach (List<TValue> valueList in Values) {
                n += valueList.Count;
            }
            return n;
        }
    }

    /// <summary>
    /// Determines whether the MultiMap contains an element with a specific
    /// key / value pair.
    /// </summary>
    /// <param name="key">Key of the element to search for.</param>
    /// <param name="value">Value of the element to search for.</param>
    /// <returns>true if the element was found; otherwise false.</returns>
    public bool Contains(TKey key, TValue value)
    {
        List<TValue> valueList;

        if (TryGetValue(key, out valueList)) {
            return valueList.Contains(value);
        }
        return false;
    }

    /// <summary>
    /// Determines whether the MultiMap contains an element with a specific value.
    /// </summary>
    /// <param name="value">Value of the element to search for.</param>
    /// <returns>true if the element was found; otherwise false.</returns>
    public bool Contains(TValue value)
    {
        foreach (List<TValue> valueList in Values) {
            if (valueList.Contains(value)) {
                return true;
            }
        }
        return false;
    }

}

Обратите внимание, что метод Add выглядит, если ключ уже присутствует. Если ключ новый, создается новый список, значение добавляется в список, а список добавляется в словарь. Если ключ уже присутствовал, новое значение добавляется в существующий список.

Ответ 5

Хотя это почти так же, как и большинство других ответов, я считаю, что это самый эффективный и сжатый способ его реализации. Использование TryGetValue выполняется быстрее, чем использование ContainsKey и переиндексация в словаре, как показали некоторые другие решения.

void Add(string key, string val)
{
    List<string> list;

    if (!dictionary.TryGetValue(someKey, out list))
    {
       values = new List<string>();
       dictionary.Add(key, list);
    }

    list.Add(val);
}

Ответ 6

Использовать имяValuedCollection.

Хорошей отправной точкой является здесь. Прямо от ссылки.

System.Collections.Specialized.NameValueCollection myCollection
    = new System.Collections.Specialized.NameValueCollection();

  myCollection.Add("Arcane", "http://arcanecode.com");
  myCollection.Add("PWOP", "http://dotnetrocks.com");
  myCollection.Add("PWOP", "http://dnrtv.com");
  myCollection.Add("PWOP", "http://www.hanselminutes.com");
  myCollection.Add("TWIT", "http://www.twit.tv");
  myCollection.Add("TWIT", "http://www.twit.tv/SN");

Ответ 7

Когда вы добавляете строку, делайте ее по-разному в зависимости от того, существует или нет ключ. Чтобы добавить строку value для клавиши key:

List<string> list;
if (dictionary.ContainsKey(key)) {
  list = dictionary[key];
} else {
  list = new List<string>();
  dictionary.Add(ley, list);
}
list.Add(value);

Ответ 8

Вместо использования словаря, почему бы не преобразовать в ILookup?

var myData = new[]{new {a=1,b="frog"}, new {a=1,b="cat"}, new {a=2,b="giraffe"}};
ILookup<int,string> lookup = myData.ToLookup(x => x.a, x => x.b);
IEnumerable<string> allOnes = lookup[1]; //enumerable of 2 items, frog and cat

ILookup - это неизменяемая структура данных, которая позволяет использовать несколько значений для каждого ключа. Вероятно, не так много, если вам нужно добавлять элементы в разное время, но если у вас есть все ваши данные вверх, это определенно путь.

Ответ 9

Вот несколько вариантов одного ответа:) Мой еще один, и он использует механизм расширения как удобный способ выполнить (удобно):

public static void AddToList<T, U>(this IDictionary<T, List<U>> dict, T key, U elementToList)
{

    List<U> list;

    bool exists = dict.TryGetValue(key, out list);

    if (exists)
    {
        dict[key].Add(elementToList);
    }
    else
    {
        dict[key] = new List<U>();
        dict[key].Add(elementToList);
    }

}

Затем вы используете его следующим образом:

Dictionary<int, List<string>> dict = new Dictionary<int, List<string>>();

dict.AddToList(4, "test1");
dict.AddToList(4, "test2");
dict.AddToList(4, "test3");

dict.AddToList(5, "test4");

Ответ 10

Существует пакет NuGet Экспериментальные коллекции Microsoft, который содержит класс MultiValueDictionary, который делает именно то, что вам нужно.

Здесь - это сообщение в блоге создателя пакета, который описывает его далее.

Здесь - еще одно сообщение в блоге, если вам интересно.

Пример использования

MultiDictionary<string, int> myDictionary = new MultiDictionary<string, int>();
myDictionary.Add("key", 1);
myDictionary.Add("key", 2);
myDictionary.Add("key", 3);
//myDictionary["key"] now contains the values 1, 2, and 3

Ответ 11

Я пытался добавить список в существующий ключ в словаре и достиг следующего решения:

Dictionary<string,List<string>> NewParent = new Dictionary<string,List<string>>();
child = new List<string> ();
child.Add('SomeData');
NewParent["item1"].AddRange(child);

Он не будет показывать никаких исключений и не будет заменять предыдущие значения.