web-dev-qa-db-fra.com

Quelle alternative aux dictionnaires en C # permet la duplication de clés?

J'ai une méthode qui renvoie des groupes de techniciens ayant travaillé sur certains projets, par exemple:

project 1 | John
project 1 | Tim
project 2 | John
project 2 | Dave

À l'origine, j'avais essayé de créer un dictionnaire, qui constituait généralement ma collection de paires clé-valeur, mais dans ce cas, je ne peux pas l'utiliser car je ne peux pas avoir une clé en double (le projet). Quelle est une alternative que je peux utiliser?

Ma seule pensée est de créer un Dictionary<Project, List<Technicians>> mais y a-t-il quelque chose de beaucoup plus facile?

31
AdamMc331

Dans votre cas, la même clé est liée aux valeurs multiple, le dictionnaire standard ne convient donc pas tel quel. Vous pouvez le déclarer comme Dictionary<Key, List<Values>>.

Mais vous pouvez aussi utiliser:

Lookup class, qui est 

Représente une collection de clés mappées chacune à une ou plusieurs valeurs.

Vous avez besoin du framework 3.5 et plus, pour cela.

44
Tigran

Ce dont vous avez besoin est une relation entre une Project et un ou plusieurs techniciens:

public class Project
{
    public ICollection<Technician> Technicians { get; set; }
}

var project = new Project();
project.Technicians = new List<Technician>()
{
    new Technician(),
    new Technician()
};

Vos objets doivent refléter les relations dans la vie réelle.

En passant, vous voudrez peut-être lire/ Conception basée sur un domaine .

public void LoadTechnicians(Project project)
{
    List<Technician> techs = new List<Technician>();

    // query the database and map Technician objects

    // Set the "Technicians" property
    project.Technicians = techs;
}
13
Greg Burghardt

Il existe un package NuGet expérimental provenant de MS qui contient MultiValueDictionary .

En gros, cela ressemble à Dictionary<Project, List<Technicians>>, sauf qu'il n'est pas nécessaire de répéter toute la logique pour gérer le Lists à chaque fois que vous y accédez.

12
svick

Je ne pense pas qu'il y a quelque chose de mal avec votre solution. Après tout, vous pouvez accéder facilement à tous les membres de l'équipe par projet. Mais alternativement, vous pouvez essayer List<KeyValuePair<Project, Technician>>. Vous conservez la relation clé-valeur, mais sans restriction de clés non répétées. Est-ce beaucoup plus simple à ce que vous avez maintenant? Dépend des cas d'utilisation.

Vous pouvez également masquer cette structure derrière l'implémentation de votre collection personnalisée.

4
PiotrWolkowski

J'ai copié ma propre réponse de ce post .

Il est assez facile de "rouler votre propre" version d'un dictionnaire qui permet les entrées "en double". Voici une mise en œuvre simple et approximative. Vous voudrez peut-être envisager de prendre en charge la plupart (sinon la totalité) de IDictionary<T>.

public class MultiMap<TKey,TValue>
{
    private readonly Dictionary<TKey,IList<TValue>> storage;

    public MultiMap()
    {
        storage = new Dictionary<TKey,IList<TValue>>();
    }

    public void Add(TKey key, TValue value)
    {
        if (!storage.ContainsKey(key)) storage.Add(key, new List<TValue>());
        storage[key].Add(value);
    }

    public IEnumerable<TKey> Keys
    {
        get { return storage.Keys; }
    }

    public bool ContainsKey(TKey key)
    {
        return storage.ContainsKey(key);
    }

    public IList<TValue> this[TKey key]
    {
        get
        {
            if (!storage.ContainsKey(key))
                throw new KeyNotFoundException(
                    string.Format(
                        "The given key {0} was not found in the collection.", key));
            return storage[key];
        }
    }
}

Un exemple rapide sur la façon de l'utiliser:

const string key = "supported_encodings";
var map = new MultiMap<string,Encoding>();
map.Add(key, Encoding.ASCII);
map.Add(key, Encoding.UTF8);
map.Add(key, Encoding.Unicode);

foreach (var existingKey in map.Keys)
{
    var values = map[existingKey];
    Console.WriteLine(string.Join(",", values));
}
0
ChristopheD