Entwickler-Ecke
Basistechnologien - String-Sortierung in multidimensionaler ArrayList
alegria - Sa 04.07.09 10:31
Titel: String-Sortierung in multidimensionaler ArrayList
Hey!
Also ich denk der Code sollte selbsterklärend sein... Problem ist halt das ich
C#-Quelltext
1: 2: 3:
| al[0][0] al[1][0] al[2][0] |
miteinander verglichen bzw. sortiert haben möchte. Ich weiss auch gar nicht ob das so prinzipiell funktioniert, denke aber schon!?
Nachdem ich nun mittels stundenlangen hin-und-her-probiere nicht weiterkomme, wende ich mich vertrauensvoll an Euch und bin für jede Hilfe dankbar!
Kleine Konsolenbeispiel:
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81:
| using System; using System.Collections.Generic; using System.Collections;
namespace ConsoleApplication1 { class Program { public class DescendingComparer : IComparer { public int Compare(object objA, object objB) { return String.Compare(objB.ToString(), objA.ToString()); } }
static void Main(string[] args) { ArrayList al = new ArrayList();
Console.WriteLine("1 für Variante 1 (funktioniert), 2 für Variante 2 (muss noch funktionieren)"); string x = Console.ReadLine();
if (x == "1") { Console.WriteLine("Variante 1:"); al.Add("Hamburg"); al.Add("Berlin"); al.Add("Zürich");
Console.WriteLine("-- unsortiert --"); foreach (string strCurrent in al) { Console.WriteLine(strCurrent); }
al.Sort(new DescendingComparer());
Console.WriteLine("\r\n-- absteigend sortiert --"); for (int i = 0; i < al.Count; i++) { Console.WriteLine(al[i]); }
} else { Console.WriteLine("Variante 2:"); al.Add(new ArrayList()); (al[al.Count - 1] as ArrayList).Add("Hamburg"); (al[al.Count - 1] as ArrayList).Add("alpha"); al.Add(new ArrayList()); (al[al.Count - 1] as ArrayList).Add("Berlin"); (al[al.Count - 1] as ArrayList).Add("beta"); al.Add(new ArrayList()); (al[al.Count - 1] as ArrayList).Add("Zürich"); (al[al.Count - 1] as ArrayList).Add("gamma");
Console.WriteLine("-- unsortiert --"); foreach (ArrayList altemp in (al as ArrayList)) { Console.WriteLine(altemp[0]); }
((al as ArrayList)).Sort(new DescendingComparer());
Console.WriteLine("\r\n-- absteigend sortiert --");
for (int i = 0; i < al.Count; i++) { Console.WriteLine((al[i] as ArrayList)[0]); }
}
Console.ReadLine();
} } } |
Mit multidimensionalen Arrays funktionierts gut (code siehe unten). Problem ist nur, dass meine ArrayList ja unterschiedlichste Datentypen besitzt/beinhaltet, und nur der erste Wert jeder ArrayList ein string (weshalb er sich m.E. ja auch zum sortieren geradezu anbietet!?) Ergo kann ich nicht einfach ArrayList zu Array transformieren...
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23:
| string[][] array = new string[3][];
array[0] = new string[3] { "apple", "apple", "apple" }; array[1] = new string[3] { "banana", "banana", "dog" }; array[2] = new string[3] { "cat", "hippo", "cat" };
for (int i = 0; i < 3; i++) { Console.WriteLine(String.Format("{0} {1} {2}", array[i][0], array[i][1], array[i][2])); }
int j = 2;
Array.Sort(array, delegate(object[] x, object[] y) { return (x[j] as IComparable).CompareTo(y[ j ]); } );
for (int i = 0; i < 3; i++) { Console.WriteLine(String.Format("{0} {1} {2}", array[i][0], array[i][1], array[i][2])); } |
Irgendjemand irgendeine Idee???
Danke im Voraus...
Moderiert von
Christian S.: Code- durch C#-Tags ersetzt
JüTho - Sa 04.07.09 10:39
Hallo,
ArrayList gehört in die Mottenkiste und sollte wie alle untypisierten Collections aus System.Collections nicht mehr benutzt werden. Verwende stattdessen List<T> und alle anderen typisierten Collections aus System.Collections.Generic. In deinem Fall kommt auch Dictionary<string, myArray> in Frage.
Gruß Jürgen
PS. Bitte markiere Code korrekt als C# (das steht in der ersten ComboBox unter "Bereiche" zur Verfügung), damit liest er sich noch besser.
alegria - Sa 04.07.09 20:06
Na gut... Scheinbar war der Code doch nicht so selbsterklärend bzw. wurde ich wohl etwas missverstanden.
| Zitat: |
| ArrayList gehört in die Mottenkiste und sollte wie alle untypisierten Collections aus System.Collections nicht mehr benutzt werden. |
Nun gut. Kann ich nicht beurteilen. Du scheinst der Fachmann zu sein. Dann nehm ich die halt nicht mehr...
| Zitat: |
| Verwende stattdessen List<T> |
Das wird schwierig. Ich habe pro "Datensatz" (ich verwende ja "multidimensionale" Arraylist in dem ich einfach pro Arraylist-Eintrag eine weitere ArrayList hinzufüge...) die unterschiedlichsten Typen. Also vom String über Integer bis Sachen wie ListViewItem oder dergleichen. Lediglich der erste Eintrag ist immer ein String und nach dem soll auch sortiert werden... Was soll ich bei so einer Anforderung mit List<T>??? Da bekomm ich doch nix multidimensionales hin!? Und wie soll ich denn dann sortieren? Kannst Du das nicht vielleicht an nem Code-Beispiel konkretisieren?
(Hab diesbzgl. noch was unter P.S. stehen...)
| Zitat: |
| In deinem Fall kommt auch Dictionary<string, myArray> in Frage. |
Puh... Ehrlich gesagt noch nie was davon gehört. Aber wenn so wie ich das sehe ein Dictionary aus einem string und noch nem Array besteht, dann hab ich ja spätestens beim Array das Problem das ich verschiedene Datentypen verwende. Und für sowas ist nun mal Arraylist besser als array. Gibts denn auch sowas wie "Dictionary<string, myArrayList>"???
P.S. Der Beispielcode war eher zur Verdeutlichung der Problematik gedacht, hat aber wahrscheinlich eher zu einer gewissen Verwirrung beigetragen. Hier mal deswegen noch fix ein Stück fix erfundenem Beispielcode wie eine multimensionale Arraylist bei mir aussehen könnte (statt der Zeile 42-50 von Post 1):
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14:
| al.Add(new ArrayList()); (al[al.Count - 1] as ArrayList).Add("Hamburg"); (al[al.Count - 1] as ArrayList).Add(1); (al[al.Count - 1] as ArrayList).Add(new string[] {"eins", "zwei", "drei"}); al.Add(new ArrayList()); (al[al.Count - 1] as ArrayList).Add("Berlin"); (al[al.Count - 1] as ArrayList).Add(6); (al[al.Count - 1] as ArrayList).Add(new string[] { "uno"}); (al[al.Count - 1] as ArrayList).Add(new List<Int32> {1, 3, 6, 8}); al.Add(new ArrayList()); (al[al.Count - 1] as ArrayList).Add("Zürich"); (al[al.Count - 1] as ArrayList).Add(3); (al[al.Count - 1] as ArrayList).Add(new string[] { "dois", "cuatro" }); (al[al.Count - 1] as ArrayList).Add(DateTime.Now); |
Kha - Sa 04.07.09 20:55
alegria hat folgendes geschrieben : |
| Ich habe pro "Datensatz" (ich verwende ja "multidimensionale" Arraylist in dem ich einfach pro Arraylist-Eintrag eine weitere ArrayList hinzufüge...) die unterschiedlichsten Typen. Also vom String über Integer bis Sachen wie ListViewItem oder dergleichen. |
Das ist mal ein merkwürdiges Datenmodell :gruebel: ... kannst du beschreiben, wo solche Daten herkommen/was genau du vorhast? Und gerade bei deinem Beispiel frage ich mich, wie dort denn nun sortiert werden sollte. Ist eine List<int> kleiner oder größer als DateTime.Now ;) ?
alegria - Sa 04.07.09 21:16
Es soll immer nach dem ersten Wert (string) innerhalb der ArrayList sortiert werden. Also [0] ist das Sortierkriterium quasi...
Was ich eigentlic vorhab?
Nun ich hab ne ListView wo man files drauf tun kann. Diese Files kommen aber erstmal in meine berühmte ArrayList und werden auf die ListView abgebildet (Das heisst die abzubildenden ListViewItem Features wanden in [i][0] alles andere an vielleicht später noch zu verwendenden Infos danach in [i][1] bis [i][n]). Klickt man buttonhoch oder mahct drag und drop oder was weis ich werden erst die Eitnräge in der Arraylist umsortiert, dann die ListView gelöscht und wieder mal alles abgebildet.
Das klappt alles fein und soweit gut. Bin zufrieden!
ABER:
Da die Files beim auswählen (openFileDialog) nicht alphabetisch sortiert in meine ArrayList wandern find ich das etwas blöd. Ich will sie also sortieren um sie dann sortiert abzubilden bevor ich vielleicht dann mittels drag&drop bissl was verschiebe in der reihenfolge...
Soweit verständlich?
P.S. Die sort Eigenschaft des ListView hilft übrigens nicht weiter...
P.S.2. Die dictionary-variante fand ich anfangs spannend:
C#-Quelltext
1:
| Dictionary<string, ArrayList> d = new Dictionary<string, ArrayList>(); |
Aber so ohne weiteres sind die wohl auch nicht zu sortieren (letzter Eintrag)...
(
http://stackoverflow.com/questions/289/how-do-you-sort-a-c-dictionary-by-value)
Kha - Sa 04.07.09 22:58
Gut, woher der jeweils erste Eintrag kommt, habe ich jetzt verstanden, aber der Rest ist mir immer noch ein Rätsel :nixweiss: . Es sieht für mich jedenfalls so aus, als ob du mit etwas Objektorientierung die Struktur deutlich verbessern könntest.
Einen Eintrag solltest du beispielsweise in einer Klasse, nennen wir sie
Item, verwalten, mit dem Stadtnamen als string-Property. Eine
List<Item> kannst du dann über
C#-Quelltext
1:
| list.OrderBy(item => item.CityName) |
sortieren.
alegria - So 05.07.09 10:09
| Zitat: |
| Es sieht für mich jedenfalls so aus, als ob du mit etwas Objektorientierung die Struktur deutlich verbessern könntest. |
Oh das kann sehr gut sein. Bin blutiger Anfänger, Laie, Hobbyprogrammierer etc. und bekannt dafür auch mal "unlogisch" zu denken bzw. etwas völlig falsch und zu kompliziert zu konstruieren.
| Zitat: |
| Einen Eintrag solltest du beispielsweise in einer Klasse, nennen wir sie Item, verwalten, mit dem Stadtnamen als string-Property. |
Klingt interessant, aber richtig codetechnisch nachvollziehen kann ich das trotzdem noch nicht... :(
Kannst Du mir nicht (ich weiss... was für eine dreistigkeit bei der beschränkten zeit heutzutage...) diesen Codeschnipsel mit Klasse, List oder was auch immer so umschreiben das alle "Datensätze"/Items sortiert nach Dateiname sortiert sind?
Das wäre echt super, weil ich es dann wahrscheinlich endlich mal nachvollziehen kann...
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12:
| al.Add(new ArrayList()); (al[al.Count - 1] as ArrayList).Add("DateinameEins"); (al[al.Count - 1] as ArrayList).Add(new ListViewItem {"Info11","Info12"}); (al[al.Count - 1] as ArrayList).Add(0); al.Add(new ArrayList()); (al[al.Count - 1] as ArrayList).Add("DateinameDrei"); (al[al.Count - 1] as ArrayList).Add(new ListViewItem {"Info31","Info32"}); (al[al.Count - 1] as ArrayList).Add(0); al.Add(new ArrayList()); (al[al.Count - 1] as ArrayList).Add("DateinameZwei"); (al[al.Count - 1] as ArrayList).Add(new ListViewItem {"Info21","Info22"}); (al[al.Count - 1] as ArrayList).Add(1); |
Kha - So 05.07.09 18:00
Da du
immer noch nicht verraten hast, woher die restlichen Daten kommen, nehme ich einfach mal eine List<object> dafür :P .
C#-Quelltext
1: 2: 3: 4: 5: 6: 7:
| class Item { public string CityName { get; set; }
List<object> data = new List<object>(); public List<object> Data { get { return data; } } } |
Um eine Liste dieser Klasse zu füllen:
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
| List<Item> list = new List<Item>();
var item = new Item(); item.CityName = "Berlin"; item.Data.Add(DateTime.Now);
...
list.Sort(delegate (Item item1, Item item2) => { return -item1.CityName.CompareTo(item2.CityName); }); |
Auf Lambda Expressions und andere 3.0-Nettigkeiten habe ich mal verzichtet, anonyme Methoden scheinen dir ja dagegen schon geläufig zu sein.
Edit: Collection Initializers hast du ja auch schon selbst benutzt. Die OOP-Grundlagen scheinen dafür noch nicht ganz so zu stecken, also hilft dir dieser Schnippsel hoffentlich :) .
alegria - So 05.07.09 19:19
| Zitat: |
| Da du immer noch nicht verraten hast, woher die restlichen Daten kommen[...] |
Alle aus dem openFileDialog - also Dateiname, -größe, -typ etc. Ein paar Eigenschaften davon will ich in der ListView anzeigen, ein paar nicht. Nach "Arraylist Schreibweise" wäre das bspw. für den "ersten Datensatz" bei [0][0] der Dateiname als String (zwecks Sortierung), [0][1] ein ListViewItem mit diversen Infos die dann abgebildet werden und [0][2] bspw. irgendein Integer der eine gewisse Zahl annimmt bspw. in Abhängigkeit der Dateigröße oder so...
Jetzt ungefähr klar wo die Daten herkommen was ich abbilden will etc.???
Bei Deinem Code ist mir hingegen noch einiges unklar...
1.
C#-Quelltext
1: 2: 3:
| var item = new Item(); item.CityName = "Berlin"; item.Data.Add(DateTime.Now); |
Ist der erste "Datensatz" und mittels Data.Add() kann ich ja genügend Zusatzinfos in Bezug auf "Berlin" hinzufügen. Soweit klar!
Wie aber mach ich ein zweites Item? Also etwas wie "Hamburg" und "Frankfurt" etc. Kleinere Versuche mittels var item2 = new Item() oder dergleichen gingen leider schief...
2. Selbst wenn ich es mal hinbekommen haben sollte (z.B. mit Deiner Hilfe... ;) ein paar items zu haben, vergleicht Deine list.sort Methode doch nur item 1 mit 2, oder? Oder soll ich dann die Klammer bei delegate einfach erweitern nach um Item item3???
Sorry aber so richtig schlau werde ich nicht draus... Hätte auch nie gedacht das ich sowas kompliziertes hier losstoße wo ich doch dachte schon ganz gut mit meinen ArrayLists unterwegs zu sein... :(
JüTho - So 05.07.09 19:33
Hat es einen wichtigen Grund, warum du nicht mit FileInfo bzw. List<FileInfo> arbeitest? Dann passt doch Sebastians früherer Vorschlag mit OrderBy. Jürgen
alegria - So 05.07.09 19:56
| Zitat: |
| Hat es einen wichtigen Grund, warum du nicht mit FileInfo bzw. List<FileInfo> arbeitest? |
Ja, weil das ganze multidimensional sein soll! Bei einer List kann ich ja nur pro Index ein object hinzufügen, oder? Mal abgesehen davon das ich natürlich auch ein Array, Arraylist oder dergleichen hinzufügen kann - aber dann sind wir wieder beim Anfang!
Ich brauch also pro Zeile/Index/Datensatz unterschiedliche Datentypen. Lediglich der erste ist immer ein string und soll auch als Sortierkriterium dienen...
Vielleicht sollte ich doch auf DataTable zurückgreifen? Da kann man doch auch jeden beliebigen Datensatz in eine Spalte reinpacken, oder?
Sorry das ich hier so banale Anfängerfragen stelle aber ich seh momentan keine richtige Lösung bei meinem Problem... :(
Kha - So 05.07.09 22:32
alegria hat folgendes geschrieben : |
| Jetzt ungefähr klar wo die Daten herkommen was ich abbilden will etc.??? |
So etwa. Aber vor allem ist es doch dann so, dass in [0][2] auch immer ein Integer mit gleicher Bedeutung steht und nicht wie in deinem Beispiel völlig verschiedene Datentypen, oder? Damit hast du effektiv durch die zweite Dimension eine Klasse nachgestellt. Eine Klasse wie FileInfo kannst du dir schließlich auch als "intelligentes Array" vorstellen: Jede ihrer Properties entspricht einem Array-Eintrag (mathematisch gesehen stellt ein Objekt genauer ein Tupel dar). Damit hat Jürgen völlig recht: eine List<FileInfo> ist äquivalent zu deinem zweidimensionalen Array primitiver Typen.
Welche Properties von FileInfo nun angezeigt werden, ist nicht Aufgabe der Liste sondern des Codes, der dann daraus die ListView erstellt, ich würde also das gesamte FileInfo-Objekt speichern. Wenn du noch zusätzliche Informationen speichern musst, könnte die Item-Klasse so aussehen:
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19:
| class Item { public FileInfo File { get; private set; } public int ZahlInAbhängigkeitDerDateigröße { get { return File.Length * 42; } }
public Item(string fileName) { File = new FileInfo(fileName); } }
...
list.Sort(delegate (Item item1, Item item2) => { return -item1.File.Name.CompareTo(item2.Name); }); |
Mit deinem 2D-Array hast du quasi "OOP Lite" erfunden, ich würde dir aber dringend empfehlen, auf die Vollversion umzusteigen :zwinker: .
alegria hat folgendes geschrieben : |
| Wie aber mach ich ein zweites Item? Also etwas wie "Hamburg" und "Frankfurt" etc. Kleinere Versuche mittels var item2 = new Item() oder dergleichen gingen leider schief... |
Sollte so funktionieren. Meistens wirst du aber wohl nicht 10 Item-Variablen anlegen, sondern eher in einer Schleife Objekte hinzufügen, z.B. so:
C#-Quelltext
1: 2: 3: 4: 5: 6:
| List<Item> list = new List<Item>(); ...
foreach (string file in dialog.FileNames) list.Add(new Item(file)); |
alegria hat folgendes geschrieben : |
| 2. Selbst wenn ich es mal hinbekommen haben sollte (z.B. mit Deiner Hilfe... ;) ein paar items zu haben, vergleicht Deine list.sort Methode doch nur item 1 mit 2, oder? Oder soll ich dann die Klammer bei delegate einfach erweitern nach um Item item3??? |
Darf ich annehmen, dass der DescendingComparer nicht von dir stammt? Sonst hättest du das Konzept eigentlich verstehen müssen ;) ...
Ich weiß auch nicht, ob du nun schon mit anonymen Methoden vertraut bist. Der wichtige Punkt ist jedenfalls: "item1" und "item2" sind
Parameter und haben nichts mit list[0] und list[1] zu tun. List<T>.Sort benötigt eine "Vergleichsmethode", die ihr mitteilt, welches von zwei Objekten das "größere" ist. Die anonyme Methode wird also beim Sortieren mehrmals mit verschiedenen Objekten als item1 und item2 aufgerufen.
alegria - Mo 06.07.09 19:34
VIELEN VIELEN DANK!!!
Hat super geklappt, wusste gar nicht wie elegant man sowas machen kann. Das mit der Item-Klasse gefällt mir sehr gut und das Sortieren ist nun auch kein Problem mehr. Einfach spitze!
Nochmals vielen Danke!!! :)
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2026 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!