158 votes

Dictionnaire à clés multiples en c# ?

Je sais qu'il n'y en a pas dans la BCL mais quelqu'un peut-il m'indiquer un bon logiciel libre ?

Par Multi, je veux dire 2 clés. ;-)

3 votes

Voulez-vous une clé composée de plusieurs attributs ou voulez-vous qu'il soit possible qu'une même clé puisse exister plusieurs fois dans le même dictionnaire ? Ces deux cas sont différents.

2 votes

0 votes

Vous pourriez ajouter un exemple d'utilisation, pour clarifier ce que vous voulez dire.

76voto

Eamon Nerbonne Points 21663

J'ai également utilisé des tuples comme jason dans sa réponse le fait. Cependant, je vous suggère de définir simplement un tuple comme une structure :

public struct Tuple<T1, T2> {
    public readonly T1 Item1;
    public readonly T2 Item2;
    public Tuple(T1 item1, T2 item2) { Item1 = item1; Item2 = item2;} 
}

public static class Tuple { // for type-inference goodness.
    public static Tuple<T1,T2> Create<T1,T2>(T1 item1, T2 item2) { 
        return new Tuple<T1,T2>(item1, item2); 
    }
}

Vous obtenez l'immuabilité, .GetHashcode et .Equals gratuitement, ce qui (en attendant C# 4.0) est très simple...

Un avertissement Toutefois, la valeur par défaut GetHashcode mise en œuvre (parfois) ne prend en compte que le premier champ alors assurez-vous que le premier champ soit le plus discriminant ou mettez en œuvre GetHashcode vous-même (par exemple, en utilisant FieldwiseHasher.Hash(this) de ValueUtils ), sinon vous risquez de rencontrer des problèmes d'évolutivité.

En outre, vous évitez les valeurs nulles qui ont tendance à compliquer les choses (et si vous voulez vraiment des valeurs nulles, il vous suffit de faire de votre Tuple<> nullable). Légèrement hors sujet, suis-je le seul à être agacé par le manque de support des références non nulles au niveau du cadre ? Je travaille sur un grand projet, et de temps en temps un null se glisse quelque part où il ne devrait pas -- et hey presto, vous obtenez une exception nullreference -- mais avec une trace de pile qui vous indique la première utilisation de la référence, pas le code réellement défectueux.

Bien sûr, .NET 4.0 est assez vieux maintenant ; la plupart d'entre nous peuvent simplement utiliser le tuple de .NET 4.0.

Edit : pour contourner les pauvres GetHashCode que .NET fournit pour les structs, j'ai écrit ValueUtils qui vous permet également d'utiliser des noms réels pour vos clés multi-champs, ce qui signifie que vous pouvez écrire quelque chose comme :

sealed class MyValueObject : ValueObject<MyValueObject> {
    public DayOfWeek day;
    public string NamedPart;
    //properties work fine too
}

... ce qui, nous l'espérons, facilitera l'utilisation de noms lisibles par l'homme pour les données ayant une sémantique de valeur, du moins jusqu'à ce que l'Union européenne (UE) adopte une stratégie de développement durable. une future version de C# implémente des tuples avec des membres nommés. ; avec des hashcodes décents, espérons-le ;-).

2 votes

Bon article sur la décision de type référence ou valeur pour les tuples dans .NET : msdn.microsoft.com/fr/us/magazine/dd942829.aspx#id0400060

0 votes

En effet (après avoir lu l'article), si vous utilisez l'implémentation par défaut des structures .Equals et .GetHashcode, un tuple avec un double qui est NaN sera égal à lui-même, même si double.NaN != double.NaN... Je peux vivre avec ça.

0 votes

Cet article dit qu'ils ont utilisé un type de référence parce qu'ils n'aimaient pas créer de la confusion en raison de l'incohérence de la sémantique entre les types struct/référence - mais je ne vois pas d'argument expliquant pourquoi un type de référence serait donc préférable ; simplement que vous aimeriez que tous les tuples soient du même type.

60voto

Jason Points 125291

J'utilise un Tuple comme les clés d'un Dictionary .

public class Tuple<T1, T2> {
    public T1 Item1 { get; private set; }
    public T2 Item2 { get; private set; }

    // implementation details
}

Assurez-vous de passer outre Equals et GetHashCode et définir operator!= et operator== selon les besoins. Vous pouvez développer le Tuple pour contenir d'autres éléments si nécessaire. .NET 4.0 comprendra une fonction intégrée Tuple .

4 votes

Consultez cet article de blog sur les tests de performance entre plusieurs implémentations de dictionnaires "multi-clé". ici

1 votes

@AronW L'article de blog n'utilise jamais une Tuple comme une clé, d'après ce que je sais ?

0 votes

Si vous devez écrire votre propre classe Tuple, autant utiliser des éléments nommés au lieu de T1, T2...

38voto

Charles Bretana Points 59899

Les tuples seront (sont) dans .Net 4.0 Jusqu'à ce moment-là, vous pouvez également utiliser un fichier

 Dictionary<key1, Dictionary<key2, TypeObject>> 

ou, créer une classe de collection personnalisée pour représenter ceci...

 public class TwoKeyDictionary<K1, K2, T>: 
        Dictionary<K1, Dictionary<K2, T>> { }

ou, avec trois touches...

public class ThreeKeyDictionary<K1, K2, K3, T> :
    Dictionary<K1, Dictionary<K2, Dictionary<K3, T>>> { }

1 votes

Réponse brillante - cela a parfaitement fonctionné pour mes besoins.

4 votes

Il ne s'agit pas d'un dictionnaire à clés multiples, mais plutôt d'une mauvaise implémentation d'un dictionnaire à clés groupées, car vous ne pouvez pas accéder aux valeurs par la deuxième clé, et vous ne pouvez pas non plus y accéder sans elle (à moins que vous ne l'obteniez par les valeurs du dictionnaire interne, mais celui-ci peut contenir plusieurs éléments). De plus, votre solution manque de code pour ajouter et supprimer des éléments.

2 votes

Jeeez... Je ne suis même pas sûr de ce dont tu parles. Tu veux un dictionnaire à plusieurs clés pour pouvoir accéder à des objets avec soit des clés ? Cela n'est en aucun cas équivalent à un tuple tel que demandé par l'op. En ce qui concerne votre deuxième question, vous vous attendez vraiment à une mise en œuvre professionnelle complète, avec toutes les cloches et les sifflets, comme réponse à la question ? Rêvez, je suis payé pour ça. Écrivez votre propre code.

6voto

Simon P Stevens Points 17536

Jetez un coup d'œil au site de Wintellect PowerCollections ( Téléchargement de CodePlex ). Je pense que leur MultiDictionary fait quelque chose comme ça.

C'est un dictionnaire de dictionnaires, il y a donc deux clés pour accéder à chaque objet, la clé du dictionnaire principal pour obtenir le sous-dictionnaire requis, puis la deuxième clé du sous-dictionnaire pour obtenir l'élément requis. Est-ce bien ce que vous voulez dire ?

1 votes

Leur MultiDictionary<,> permet d'attribuer plusieurs valeurs à une seule clé, et non d'avoir plusieurs clés dans ce sens.

1 votes

Mais la question de l'OP est aussi vague qu'elle peut l'être. Donc +1 pour un point de vue différent.

0 votes

@pbalaga a raison, PowerCollections ne vous permet pas d'avoir deux clés (downvoted à cause de cela).

5voto

JSBձոգչ Points 25069

Y a-t-il un problème avec

new Dictionary<KeyValuePair<object, object>, object>?

3 votes

Existe-t-il une classe intégrée Pair<T1, T2> ?

0 votes

@MichaelDonohue : A partir de .NET 4.0, il y a la Tuple classe.

4 votes

Oui, il y a un problème : KVP utilise ValueType.GetHashCode - "Si vous appelez la méthode GetHashCode du type dérivé, il est peu probable que la valeur de retour puisse être utilisée comme clé dans une table de hachage." KVP est un choix totalement inapproprié pour une clé de dictionnaire et pourrait donner lieu à de nombreuses collisions.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X