J'ai un groupe de données qui ressemble à ceci: maintenant, certainement, je pourrais créer un tableau de chaîne [x] [y] = z, mais ce tableau doit être redimensionnable et je préférerais utiliser les représentations de chaîne des indexeurs que de convertir en numérique. La raison en est que je devrai rechercher les données par chaîne, et je ne vois pas le point dans les conversions de chaîne inutiles-> Number. P> Ma première pensée était la suivante: P> Dictionary<string, Dictionary<string, string>> data;
data = new Dictionary<string, Dictionary<string, string>>();
Dictionary<string, string> subdata = Dictionary<string, string>();
subdata.Add(key, string);
data.add(key2, subdata);
6 Réponses :
serait un LISTE
TRAVAIL POUR VOUS ? Toujours kludgy, mais meilleur que les dictionnaires Imho.
Edit: Qu'en est-il d'un dictionnaire Dictionnaire
string GetKey(string a, string b) {
return a + "\0" + b;
}
Comme je l'ai dit, je préférerais indexer les indexer par chaîne. Et ils peuvent ne pas toujours être séquentiels (pourraient avoir un nombre manquant au milieu).
Oh, ok ... Je pense que votre mention de matrices multidimensionnelles nous a jeté de côté (car celles n'auraient pas été indexées par des chaînes non plus).
Je pense que cela dépend vraiment de ce que vous modélisez ici. Si vous envisagez d'utiliser une approche orientée objet, vous ne devriez pas y penser comme des éléments arbitraires dans une structure de données.
Je devine de regarder cela que les deux premières colonnes servent de " clé "pour les autres articles. Définissez une structure simple et créez un dictionnaire de la même manière: P>
struct Key { public int Val1 { get; set; } public int Val2 { get; set; } } .... Dictionary<Key, string> values;
Je ne suis pas sûr que cela fait ce que vous avez l'intention. Ou peut-être que cela fait parce que vous utilisez une structure (type de valeur). Tous les key.val1, Key.Val2 sont-ils égaux si elles contiennent les mêmes données?
J'aime cette approche. Vous auriez probablement besoin de mettre en œuvre Icomarer ou égal.
C'est-à-dire que cela revient-il vrai? Nouvelle clé {VAL1 = 1, VAL2 = 2} == nouvelle touche {VAL1 = 1, VAL2 = 2};
Oui, désolé - vous auriez besoin de mettre en œuvre IComparer et égal. Je ne suis pas sûr à 100% sur l'évaluation clé, mais je suis assez sûr que cela fonctionnerait. Besoin de tests et tout ce jazz.
Cette approche est très similaire aux approches spécifiées par moi-même et DTB dans nos modifications, mais elle utilise une structure plutôt qu'une concaténation à la chaîne. L'exemple ci-dessus est incomplet; Icomarer et / ou égaux doivent être mis en œuvre / répréhensibles, mais autres que cela, c'est une approche très solide.
Gethashcode devrait probablement être remplacé aussi bien, étant donné que le dictionnaire utilisera probablement une hache en interne.
Oui, cela ressemble à une meilleure solution que votre approche d'encapsulation dans une nouvelle classe. Il résout le problème de l'accès au complément complet de la fonctionnalité de dictionnaire sans écrire un code d'emballage.
Par exemple: P> Liste
public class TwoDimensionalDictionary
{
private Dictionary<string, string> Items = new Dictionary<string, string>();
public string this[string i1, string i2]
{
get
{
// insert null checks here
return Items[BuildKey(i1, i2)];
}
set
{
Items[BuildKey(i1, i2)] = value;
}
}
public string BuildKey(string i1, string i2)
{
return "I1: " + i1 + " I2: " + i2;
}
}
C'est une solution intéressante, mais je vois des problèmes avec des cas de bord. Ils pourraient être résolus cependant. Par exemple, si I1, I2 n'existe pas, cela lancera une exception. Aucun moyen d'accéder à la fonctionnalité "Essayez" ou à faire un si (items.keys.exists (..)). Cela impliquerait donc d'écrire beaucoup de code Wrapper, que j'essaie d'éviter pour des raisons de maintenance.
Très vrai. Comme je l'ai dit, c'est un début, pas une solution. Cela dit, vous aurez les mêmes problèmes que vous avez mentionnés même si vous allez le dictionnaire
C'est une demande assez courante et la plupart des gens finissent par écrire une variation d'une classe de tuple. Si vous utilisez ASP.NET, vous pouvez utiliser la classe Il y a une classe générique de trois tuples , vous pouvez donc créer une nouvelle liste EDIT: une liste avec un dictionnaire ne semble pas être la bonne approche, car chaque dictionnaire n'entre qu'une seule valeur. Il n'y a pas de relation multi-entrées entre la clé et les valeurs - il existe simplement une touche multi-pièces et une valeur associée. Les données sont équivalentes à une ligne de base de données (ou tuple!). P> Edit2: Voici une classe de liste indexable que vous pourriez utiliser pour plus de commodité. P> triple code> déjà disponible, sinon, écrire quelque chose comme:
public class MyTupleList : List<Tuple<string, string, string>>
{
public Tuple<string, string, string> this[string first, string second]
{
get
{
return (this.Find(x => x.First == first && x.Second == second));
}
set
{
this[first, second] = value;
}
}
}
J'avais pensé à cela, mais je ne pouvais pas voir un bon moyen de rechercher des objets sans marcher toute la liste et de comparer des valeurs. Vous pouvez le faire avec Linq, mais je ne peux pas être sûr que cela sera toujours utilisé avec C # 3 ou plus. Cela signifie que je devrais ajouter tout le code de recherche de recherche qui, comme vous le savez probablement, n'est pas facile à obtenir.
Je vais vous donner un exemple complet dans une minute, vous allez adorer;)
Merci pour le bel exemple. Mais comme je l'ai dit dans mon commentaire, je ne peux pas être sûr qu'il sera toujours utilisé avec C # 3, alors Linq, tandis qu'une belle solution au problème, n'est pas une option. Et bien qu'un exercice intéressant, je ne veux vraiment pas passer mon temps à écrire un bon code d'indexation, c'est ce que les classes de collecte existantes sont censées nous aider à éviter;)
Eh bien, cela dépend de la flexible dont vous avez besoin de la recherche de la clé. Ce n'est vraiment qu'une version générique de ce que propose Ryan et John proposent, qui sont probablement les meilleures réponses ici, l'exemple d'indexation est simplement la cerise, ce n'est même pas nécessaire. Et c'est simple de faire la même chose sans Linq;)
Je pense que je vais vous donner la réponse quand même, car c'est une bonne solution.
Vous avez besoin du code pour compiler sur différentes versions du compilateur ou pour exécuter différentes versions du temps d'exécution? C # 3 compilé DLL / Programmes exécutés sur le V2 de l'exécution. LINQ est Syntaxtic Suggar et est simplement compilé dans des appels de méthode statiques réguliers. (Toutes les méthodes d'extension sont le sucre syntaxique compilé dans des appels de méthode statiques)
Compiler sur différentes versions du compilateur. Ceci est générique, par définition, il a donc besoin de pouvoir créer les types à la compilation.
donné une paire * une classe avec égalité et code de code de hachage, rien terriblement dur. sup> p> appropriée code> classe *, laissé comme un exercice pour le lecteur , vous pouvez utiliser un dictionnaire
Pour cette question particulière, on pourrait utiliser le point ( docs.microsoft. com / fr-nous / dotnet / API / System.Drawing.point ) au lieu de la créer de sorte qu'il devient Dictionnaire
Si vous allez jamais avoir besoin de trouver z code> par indiqué
(x, y) code> (et non, par exemple, trouvez tout
y code > Par
x code>), utilisez-le:
Dictionary<KeyValuePair<string, string>, string>
Vous avez dit qu'ils pourraient ne pas être séquentiels, mais sont-ils toujours commandés? Votre choix de liste de liste par rapport au dictionnaire est affecté par cela, bien que vous puissiez toujours avoir un énumérateur qui trie avant d'être énuméré.
La liste ne peut être indexée que séquentiellement. Si vous supprimez un élément de la liste, l'élément + 1 devient l'élément - 1 dans l'index, cela ne fonctionne donc pas. Ils doivent être indexés par leurs valeurs.
Je vois que beaucoup de vos commentaires consistent à éviter d'écrire une enveloppe "pour la maintenance". Vous devez reconsidérer cette position, car vous constaterez probablement que la rédaction d'une classe d'emballage facilite le code, le test et le maintien à long terme et non l'inverse. L'encapsulation est une excellente installation de la programmation OO. Sinon, vous finissez par pousser toute la logique et ajouter un couplage inutilement au code de la consommation, ainsi que le stockage et la mise en œuvre de couple étroitement. Écrivez vos cas de test avant d'écrire l'emballage, et ce sera tout à fait évident quelle interface vous devez entretenir.
Ma position sur le code Wrapper va bien au-delà des raisons de maintenance. Je suis de l'état d'esprit de principe sec et je trouve un code d'emballage pour violer assez souvent ce principe (même si vous ne répétez pas le code à l'intérieur, vous répétez la chaudière). Je préfère les solutions dans lesquelles je n'ai pas à emballer. La solution de Ryan, par exemple, ne nécessite aucun code d'emballage et atteint le même résultat. Je trouve que c'est une solution supérieure.
De plus, beaucoup de travail et d'efforts sont entrés dans les classes de collecte de la BCL et leurs méthodes d'accès sont bien recherchées et (espérons-le) sans bug. Si je dois recréer beaucoup de ce code, des statistiques simples diront que je ne le créerai plus aussi près que si je ne consacre à ne pas les concevoir de temps similaires. Il est vraiment facile de tourner quelque chose qui est O (1) dans O (n) ou O (n ^ 2) ou O (log n) ou pire si vous ne faites pas attention. De plus, lorsque vous encapsulez quelque chose avec beaucoup de fonctionnalités, comme le dictionnaire, vous devez écrire beaucoup d'emballages si vous avez besoin de cette fonctionnalité.
Forcer les utilisateurs de votre bibliothèque à passer autour du dictionnaire> ne va pas au curry de leur faveur avec eux, surtout lorsqu'il lie leur code à votre mise en œuvre d'une structure de données. Les bonnes pratiques oo disent que vous ne le faites pas. La classe que vous établissez devrait toujours utiliser les classes de collecte générique en interne, de sorte que vous n'affecterez pas les caractéristiques des Big-O, pas plus que vous êtes susceptible d'introduire des bugs. Ilist est quelque chose comme 9 méthodes. J'ai fait une enveloppe l'autre jour parce que j'ai imposé une sémantique différente sur ma liste, et cela m'a pris toutes les 10 minutes, y compris des tests unitaires.