web-dev-qa-db-fra.com

dictionnaire c # Comment ajouter plusieurs valeurs pour une clé unique?

J'ai créé un objet dictionnaire 

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

Je souhaite ajouter des valeurs de chaîne à la liste de chaînes pour une clé unique donnée . Si la clé n'existe pas déjà, je dois ajouter une nouvelle clé. List<string> n'est pas prédéfini, je veux dire que je n'ai créé aucun objet de liste, puis fourni à dictionary.Add("key",Listname). Comment créer dynamiquement cet objet de liste dans dictionary.Add("key",Listname) puis ajouter des chaînes à cette liste. Si je dois ajouter 100 clés, dois-je créer 100 listes avant d'exécuter l'instruction dictionary.Add et dois-je également définir le contenu de ces listes?

Je vous remercie. 

19
sailer

Mise à jour: vérifie l'existence à l'aide de TryGetValue pour ne faire qu'une recherche dans le cas où vous avez la liste:

List<int> list;

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

list.Add(2);


Original: Vérifiez l'existence et ajoutez une fois, puis entrez le dictionnaire pour obtenir la liste et ajoutez-le à la liste comme d'habitude:

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);

Ou List<string> comme dans votre cas.

Soit dit en passant, si vous savez combien d'éléments vous allez ajouter à une collection dynamique telle que List<T>, privilégiez le constructeur prenant la capacité de liste initiale: new List<int>(100);.

Cela récupérera la mémoire requise pour satisfaire la capacité spécifiée upfront, au lieu de récupérer de petits morceaux à chaque fois qu'il commence à se remplir. Vous pouvez faire la même chose avec les dictionnaires si vous savez que vous avez 100 clés.

28
Adam Houldsworth

Si j'ai compris ce que tu veux:

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

plus tard... 

dictionary["key"].Add("string to your list");
8
Reniuz
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");
}

Si la clé n'existe pas, une nouvelle List est ajoutée (à l'intérieur de si). Si la clé existe, il suffit d'ajouter une nouvelle valeur à la variable List sous cette clé.

6
Zelter Ady

Vous pourriez utiliser mon implémentation d'une carte multiple, qui dérive d'un Dictionary<K, List<V>>. Ce n'est pas parfait, mais cela fait du bon travail.

/// <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;
    }

}

Notez que la méthode Add recherche si une clé est déjà présente. Si la clé est nouvelle, une nouvelle liste est créée, la valeur est ajoutée à la liste et la liste est ajoutée au dictionnaire. Si la clé était déjà présente, la nouvelle valeur est ajoutée à la liste existante.

Bien que presque identique à la plupart des autres réponses, je pense que c'est la manière la plus efficace et la plus concise de la mettre en œuvre. L'utilisation de TryGetValue est plus rapide que l'utilisation de ContainsKey et la réindexation dans le dictionnaire, comme le montrent d'autres solutions.

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);
}
2
roken

Utilisez NameValuedCollection. 

Bon point de départ est ici . Directement du lien.

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”);
2
Sandeep

Au lieu d'utiliser un dictionnaire, pourquoi ne pas convertir en 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 est une structure de données immuable qui permet plusieurs valeurs par clé. Ce n'est probablement pas très utile si vous devez ajouter des éléments à des moments différents, mais si vous avez toutes vos données à l'avance, c'est certainement la voie à suivre.

0
spender

J'essayais d'ajouter List à une clé existante dans le dictionnaire et j'ai atteint la solution suivante:

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

Il ne montrera aucune exception et ne remplacera pas les valeurs précédentes.

0
superB

Voici plusieurs variantes de la réponse :) My en est une autre et utilise le mécanisme d’extension comme moyen pratique d’exécuter (pratique):

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);
    }

}

Ensuite, vous l'utilisez comme suit:

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");
0
Bronek

Il existe un package NuGet Microsoft Experimental Collections qui contient une classe MultiValueDictionary qui répond exactement à vos besoins. 

Ici est un article de blog du créateur du paquet qui le décrit plus en détail.

Ici est un autre article de blog si vous vous sentez curieux.

Exemple d'utilisation:

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
0
Domysee

Lorsque vous ajoutez une chaîne, procédez différemment selon que la clé existe déjà ou non. Pour ajouter la chaîne value à la clé key:

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