Welche Collection
-
Hallo,
ich habe folgende Datenstruktur: Eine Infostruktur (IS) mit bestimmten Infos und jeder IS sind n Elemente (E) zugeordnet. Also z.B. so:
IS1: E1, E2, E4
IS2: E2, E9, E11, E2
usw.Welche Datenstruktur nehm ich da am besten in C#?
Im Moment dachte ich an folgendes:
List<IS> infos;
List<List<E>> elemente;D.h. in der Liste elemente[0] wären dann alle Elmente der IS1 (sprich infos[0]) gespeichert. Aber geht das auch besser/eleganter?
Danke
-
besser eine Klasse IS erstellen mit einer Eigenschaft List<E>. Dann die Klasse in eine List packen.
sonst hat du die Daten getrennt in zwei Listen. Was viele Nachteile hat.
Zum Beipiel wenn:- ein Instanz von IS an an einer Funktion übergeben willst, musst du auch immer in einem zweiten Parameter die E's mit übergeben.
- Bei Sortierungen der Liste mit IS.
- Beim Einfügen oder entfernen von Einträgen in den Listen.
-
Hallo AndreasW,
erstmal Danke für die Antwort!
Noch eine Frage zu deiner Struktur:
Ich werde sehr sehr oft den Fall haben, dass ich ein E habe und dazu die passende IS suche. Welche Datenstruktur ist dafür am besten? Ist eine Liste schnell beim Suchen?Danke
-
naja, das von mir erwähnte Modell ist eher auf den umgekehrten Fall spezialisiert.
Das Suchen darin geht recht gut. Allerdings ist nur das Suchen von IS's performant.Wenn du öffters nach IS's eines E suchst, dann kannst du besser die Struktur umdrehen. In jedes Element eine Liste der IS-Objekte
Du kannst aber auch beides machen:
class Info { //... irgendwas public List<Element> Elements; } class Element { //... irgendwas public List<Info> Infos; }
Hat den Vorteil der schnellen Suche in beiden Richtungen. Nachteil ist der höhere Speicherbedarf und die aufwändigere Initialisierung der Objekte.
Wenn häufiger suchst als iterierst, dann kannst du sowieso besser die Einträge in einer Dictinary packen.
Was du in die Dictinary packst hängt, wie gesagt davon ab, was du häufiger suchst.Dictinary<int, Info> infoMap; // um nach Es von IS zu suchen Dictinary<int, Element> elementMap; // um nach ISs von E zu suchen
die Keys musst du natürlich anpassen.
Besser ist es natürlich immer, sich auf eine Suchrichtung zu beschränken.Die Abbildung der Daten würde ich aber (fast) immer in Klassen vornehmen. Das erhöht die Übersichtlichkeit und Lesbarkeit von Quellcode enorm und ist besser wartbar.
Was wann wie und wo am Besten ist, hängt immer von der Situation ab.
in der Regel bezahlt man mehr Performance mit mehr Speicherbedarf und umgekehrt. Auch da muss man halt immer einen gesunden Kompromiss finden.
- Wird viel gesucht? -> Dann meist eine Dictinary
- Wird viel iteriert und manchmal gesucht? -> Dann eher eine liste und vielleicht eine zusätzliche Dictinary in der suchenden Routine, wenn der Performancegewinn dieses rechtfertigt.Du stellst dir diese Fragen nun wahrscheinlich am Anfang deiner Implementation. Wahrscheinlich kannst du deshalb zu diesen Zeitpunkt auch noch nicht einmal vollständig sagen, wie die Anforderungen nach Vollendung der Implementation aussieht. Deshalb gehe ich bei einer Situation wie du sie nun hast (die Entscheidung der Datenhaltung) anders vor.
Sobald ich feststelle, dass eine Datenstruktur wähst, lagere ich den Zugriff auf die Datenstruktur in eine eigene Klasse aus. Eine Klasse, die das Suchen und Iterieren verwaltet. Dort kann man dann halt nach Elementen einer InfoStruktur fragen und umgekehrt. Die Art und Weise der Datenhaltung ist aber nur dieser Klasse bekannt.
Ich implementiere also erst einmal und kümmere mich nicht wirklich Performance-Fragen. Das hat den Vorteil, dass ich den Implementierungsfluss nicht verliere und habe aber dafür gesorgt, dass ich nach der Implementierung ein eventuelles Performance-Problem beseitigen kann, ohne den Code zu verändern, der die Daten benutzt.
NAch der Implementierung, meistens während der Testphase, baue einfach die Datenhaltung um, so wie sie benötigt wird. Zu diesen Zeitpunkt kenne ich dann ja alle Anforderungen an die Datenhaltung. Per Logging und mit den VS-Performance-Tools kann ich dann sogar feststellen, wie die Datenhaltung optimal gestaltet werden kann. Bei sehr großen Datenmengen kann es sogar vorkommen, dass man die Daten in meheren Datencontainern packt um Performancevorteile zu gewinnen. So wie deine Anforderung in beiden Richtungen performant suchen zu können.
Bei der Implementierung der Routinen, die diese Daten verwenden, mache ich mir darüber aber keine gedanken. Da konzentriere ich mich auf die Routine die ich zu schreiben habe.Fazit: Durch deine Vorgehensweise, so wie du sie im ersten Beitrag geschildert hast, machst du dein Code von der Datenhaltung abhängig. Und das darf nicht geschehen. Damit verbaust du dir spätere Änderungen, die sehr sehr wahrscheinlich sind.
Bilde die "Tatsächliche" Datenstruktur in Klassen ab und kapsel die Zugriffe in eine andere Zugriffs-Klasse und benutzte bei der Implementierung der Routinen, die diese Daten benutzen nur die Zugriffs-Klasse um an die Daten zu kommen. Dann kannst du dich auf die eigentliche Implementierung konzentrieren ohne Angst zu haben, später nichts mehr ändern zu können.
-
AndreasW schrieb:
Du kannst aber auch beides machen:
class Info { //... irgendwas public List<Element> Elements; } class Element { //... irgendwas public List<Info> Infos; }
Kenne mich in C# nicht aus, aber bist du sicher, dass so was jemals möglich sein wird? Klasse Info kann ohne Elemt nicht erzeugt werden und Element ohne Info nicht...
Gruß Patrick
-
Dummie schrieb:
Kenne mich in C# nicht aus, aber bist du sicher, dass so was jemals möglich sein wird? Klasse Info kann ohne Elemt nicht erzeugt werden und Element ohne Info nicht...
das ist ja nicht richtig. Einen Konstruktor hab ich nicht definiert.
Wie sinnvoll das ist, ist allerdings durchaus fraglich. Ich hab das Beispiel auch nur angeführt um aufzuzeigen, dass man eine Datenstruktur so gestalten kann, dass man in beiden Richtungen suchen kann. Das ist prinzipell auch machbar. Im weiteren Text habe ich auch beschrieben, wie man sowas vermeidet.