tutorials.de Buch-Aktion 05/2012
Like Tree1Danke
  • 1 Beitrag von fassy
ERLEDIGT
NEIN
ANTWORTEN
9
ZUGRIFFE
2294
EMPFEHLEN
  • An Twitter übertragen
  • An Facebook übertragen
AUF DIESES THEMA
ANTWORTEN
  1. #1
    Steve222 Steve222 ist offline Mitglied Bronze
    Registriert seit
    Mar 2007
    Ort
    Rheinland
    Beiträge
    46
    Guten Tag,

    hier eine weitere Frage und eine herzliches Danke für Beachtung oder sogar Beantwortung dieser Frage.

    Wie kann ich ein TreeSet flexibel und nach verschiedenen Kriterien sortieren?

    Sachverhalt:

    TreeSet implementiert sortedSet und gilt (daher!?) als sortiert, bzw. sortiert automatisch.

    Wenn nun Objekte des Typs Person in ein TreeSet ts sollen, dann muss
    die class Person Comparable implementieren.

    Sobald mehr als ein einzelnes Objekte des Typ Person in ts hinzugefügt werden soll,
    wird die Überschreibung von compareTo(E o) gefordert.

    public int compareTo(E o) ist einzige Methode in Comparable.

    compareTo(E o) kann sich nur auf EIN Attribut von Person-Objekt beziehen, nämlich das was ich auswähle, denn über die Parameterliste von compareTo(...) ist keine Steuerung möglich.

    Wenn ich meine Person Objekte nach jeweils einem anderen Attribut sortieren will
    dann geht das in einem Programmlauf und ohne Abändern der compareTo(E o) -Überschreibung wohl nicht.

    Wenn ich meine Person Objekte nach jeweils einem anderen Attribut sortieren will,
    dann ist TreeSet anscheinend ungeeignet, oder?

    Da muss ich vermutlich die Person-Objekte in eine andere Collection (z.B. List ) speichern und jeweils verschiedene Comparatoren
    darauf anwenden, oder ?


    Viele Grüße
    Steve222
     

  2. #2
    fassy fassy ist offline Mitglied Bronze
    Registriert seit
    Jan 2010
    Beiträge
    42
    Nicht ganz, du kannst ja in dem Objekt Person einen SortKey angeben:


    Code java:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    
    /* [...] */
    pivate int sortKey = 0; // default sort by first field
    /* [...] */
    @Override
    public int compareTo(Object o) {
        Person p = (Person) o;
        switch(sortKey ){
            case 0: { return this.getFirstName().compareTo(p.getFirstName()); }
            /* [...] */
           default: { return this.getFirstName().compareTo(p.getFirstName()); }
           }
    }
    /* [...] */

    Musst dann nur noch den Objecten den Sortkey zuweisen, oder aber den Sortkey irgend wo anders her bekommen.

    viele Grüße
    f.
     

  3. #3
    Steve222 Steve222 ist offline Mitglied Bronze
    Registriert seit
    Mar 2007
    Ort
    Rheinland
    Beiträge
    46
    Hallo fassy und
    vielen Dank für den schnellen Hinweis.

    Dann können nur genau die Person-Instanzen miteinander verglichen und sortiert werden, die den gleichen sort-Key haben.

    Aber was, wenn einige Person-Instanzen den einen .sortKey haben und andere Person-Instanzen einen anderen?
    Spontan stelle ich es mir mühsam vor, jeder Person-Instanz einen sortkey zuzuweisen und den jedesmal abzuändern
    wenn nach einem anderen Merkmal sortiert werden soll.


    Code java:
    1
    2
    3
    4
    5
    6
    7
    8
    
    Person objPerson1 = new Person()
    Person objPerson2 = new Person()
    Person objPerson3 = new Person()
    Person objPerson4 = new Person()
    objPerson1.sortKey = 2;
    objPerson2.sortKey = 1;
    objPerson3.sortKey = 2;
    objPerson4.sortKey = 1;

    Oder denke ich verkehrt?

    Viele Grüße

    Steve222
     

  4. #4
    Steve222 Steve222 ist offline Mitglied Bronze
    Registriert seit
    Mar 2007
    Ort
    Rheinland
    Beiträge
    46
    Nachtrag:

    Ich denke sortKey darf als private deklariert werden, oder?
     

  5. #5
    Steve222 Steve222 ist offline Mitglied Bronze
    Registriert seit
    Mar 2007
    Ort
    Rheinland
    Beiträge
    46
    Nachtrag zu Nachtrag:

    Ich wollte miteilen, dass meines Erachtens sortKey NICHT als private deklariert werden darf, sondern
    als public oder ggf. protected.
     

  6. #6
    fassy fassy ist offline Mitglied Bronze
    Registriert seit
    Jan 2010
    Beiträge
    42
    Zitat Zitat von Steve222 Beitrag anzeigen
    Ich wollte miteilen, dass meines Erachtens sortKey NICHT als private deklariert werden darf, sondern
    als public oder ggf. protected.
    Warum solltest du das tun wollen? Ich würde in Java niemals eine Membervariable public deklarieren. Maximal protected und dann auch nur wenn sie in vererbten Klassen weiter genutzt werden soll. Public sollten nur Konstanten sein. 5 Zeilen für einen Getter und nochmal 5 für einen Setter hat man immer über. Wenn du irgendwann mal deine Meinung änderst was den Zugriff auf das Feld angeht musst du nur die Getter und Setter anpassen, nicht jede Klasse die auf das public deklarierte Feld zugreift. Aber das ist eine Glaubens und Design Frage - aber der Zugriff über public direkt auf Objektvariablen ist kein guter Stil und wiederspricht dem OOP Prinzip der DatenKapselung und Abstraktung

    Zitat Zitat von Steve222 Beitrag anzeigen
    Dann können nur genau die Person-Instanzen miteinander verglichen und sortiert werden, die den gleichen sort-Key haben.

    Aber was, wenn einige Person-Instanzen den einen .sortKey haben und andere Person-Instanzen einen anderen?
    Spontan stelle ich es mir mühsam vor, jeder Person-Instanz einen sortkey zuzuweisen und den jedesmal abzuändern
    wenn nach einem anderen Merkmal sortiert werden soll.
    Du solltest deine Requirements überdenken. Wann soll sortiert werden? Normalerweise wird beim einfügen in die Map sortiert, d.h. das neue Object wird an die richtige Position geschoben. Das Treeset sortiert nicht automatisch alle anderen Objekte mit um.

    Natürlich macht es Sinn nur Objekte mit dem gleichen Sortkey in einem Set zu halten, das ist schließlich der Gedanke hinter einem SortedSet. Ich verstehe halt nicht so ganz was du vorhast, also die Frage ist was möchtest du machen? Wenn du das Set dynamisch umsortieren willst musst du so vorgehen:

    1) Sortiere nach Vorname in Set1
    2) ändern des sortkeys, also Set1 umsortieren
    2.1)alle sortkeys der Object in set1 auf den neuen sortkey setzen
    2.2)neue TreeSet anlegen
    2.3)alle Objecte in das neue Set schieben

    Code java:
    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
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    
    import java.util.Iterator;
    import java.util.Set;
    import java.util.TreeSet;
     
    public class Test {
        public static final int SORT_BY_FIRSTNAME = 0;
        public static final int SORT_BY_LASTNAME = 1;
     
        public static void main(String[] args) {
     
            Person a = new Person("Klaus", "Heinze");
            Person b = new Person("Mara", "Schmidt");
            Person c = new Person("Werner", "Meier");
            Person d = new Person("Stephanie", "Maier");
            Person e = new Person("Ruth", "Mayer");
            Person z = new Person("Arno", "Zitter");
            z.setSortKey(SORT_BY_LASTNAME);
     
            Set<Person> persons = new TreeSet<Person>();
            persons.add(a);
            persons.add(b);
            persons.add(c);
            persons.add(d);
            persons.add(e);
     
            System.out.println("SORTED BY FIRSTNAME:");
             printSet(persons);
    /* 
    SORTED BY FIRSTNAME:
    Klaus Heinze
    Mara Schmidt
    Ruth Mayer
    Stephanie Maier
    Werner Meier
    */
     
            persons.add(z);
            System.out.println("\nSORTED BY FIRSTNAME:");
            printSet(persons);
    /*
     
    SORTED BY FIRSTNAME:
    Klaus Heinze
    Mara Schmidt
    Ruth Mayer
    Stephanie Maier
    Werner Meier
    Arno Zitter              <-- am Ende eingefügt worden, das sortKey für den Kollegen 1 ist...  
    */
            
            persons = sortSet(persons, SORT_BY_LASTNAME);
            System.out.println("\nSORTED BY LASTNAME:");
            printSet(persons);
    /*
    SORTED BY LASTNAME:
    Klaus Heinze
    Stephanie Maier
    Ruth Mayer
    Werner Meier
    Mara Schmidt
    Arno Zitter
    */
            persons = sortSet(persons, SORT_BY_FIRSTNAME);
            System.out.println("\nSORTED BY FIRSTNAME:");
            printSet(persons);
    /*
    SORTED BY FIRSTNAME:
    Arno Zitter
    Klaus Heinze
    Mara Schmidt
    Ruth Mayer
    Stephanie Maier
    Werner Meier
    */
     
     
        }
     
        private static Set<Person> sortSet(Set<Person> set, int sortKey) {
            Set<Person> newSet = new TreeSet<Person>();
            for ( Iterator<Person> i = set.iterator(); i.hasNext();){
                     Person p = i.next();
                     p.setSortKey(sortKey);
                     newSet.add(p);
            }
            return newSet;
        }
        
        private static void printSet(Set<Person> set){
            for (Iterator<Person> i = set.iterator(); i.hasNext();) {
                Person p = i.next();
                System.out.println(p.getFirstName() + " " + p.getLastName());
            }
        }
    }
     
    class Person implements Comparable {
        private String firstName;
        private String lastName;
        private int sortKey = 0;
     
        public Person(String firstName, String lastName) {
            this.firstName = firstName;
            this.lastName = lastName;
        }
     
        @Override
        public int compareTo(Object o) {
            Person p = (Person) o;
            switch (sortKey) {
            case 0: {
                return this.getFirstName().compareTo(p.getFirstName());
            }
            case 1: {
                return this.getLastName().compareTo(p.getLastName());
            }
            default: {
                return this.getFirstName().compareTo(p.getFirstName());
            }
            }
        }
     
        public String getFirstName() {
            return firstName;
        }
     
        public void setFirstName(String firstName) {
            this.firstName = firstName;
        }
     
        public String getLastName() {
            return lastName;
        }
     
        public void setLastName(String lastName) {
            this.lastName = lastName;
        }
     
        public int getSortKey() {
            return sortKey;
        }
     
        public void setSortKey(int sortKey) {
            this.sortKey = sortKey;
        }
     
    }

    Die Frage ist und bleibt was du eigentlich vorhast. Du kannst ja auch ein Event/Listener Konzept fahren, d.h. wenn ein sortKey geändert wird triggert das eine Neusortierung. Oder du überschreibst die add Methode des Set und sortierst neu beim Einfügen wenn der sortKey nicht passt. Aber in einem Set nach verschiedenen Keys zu sortieren macht keinen Sinn. Das Set verschieden sortiert ausgeben schon, das kannst du machen wie in meinem Beispiel indem du die sortSet Methode aufrust und dann mit dem nach deinen Wünschen Sortierten Set arbeitest.

    Viele Grüße
    f.
    Geändert von fassy (23.01.10 um 01:27 Uhr)
    Steve222 bedankt sich. 

  7. #7
    Avatar von zeja
    zeja zeja ist offline Mitglied Diamant
    tutorials.de Premium-User
    Registriert seit
    Sep 2006
    Beiträge
    2.962
    Du kannst dem Konstruktor des TreeSet einen Comparator mitgeben. Der funktioniert im Prinzip genauso wie Comparable nur dass er eben zwei zu vergleichende Objekte bekommt. Dadurch kannst du je nach Situation einen anderen Comparator mitgeben und bist nicht darauf angewiesen dass deine Person Comparable ist oder wie Comparable dort implementiert ist.
     

  8. #8
    Pretor777 Tutorials.de Gastzugang
    Wenn du mit einem TreeSet Strings vergleichst solltest du besser einen Collator (http://java.sun.com/javase/6/docs/ap...lator.html)als comperator verwenden.
     

  9. #9
    Avatar von Vereth
    Vereth Vereth ist offline Mitglied Brokat
    Registriert seit
    Nov 2009
    Ort
    Dortmund
    Beiträge
    372
    Für dein Problem hast du dir leider die falsche Programmiersprache ausgesucht; in C# würde ich das Problem folgendermaßen lösen. Ich verwalte die Daten in einem DataSet an, in dem ich die notwendigen Tabellen definiere, füge unter Umständen die notwendigen Indices hinzu, und hole die gewünschten Daten mit Hilfe eines geeigneten SQL-Statements. Als Ergebnis bekomme ich dann ein DataSet, das ich entweder direkt als DataSource einem Anzeigeelement zuweise oder in die benötigten Objekte und Verwaltungsstrukturen umwandle. Dies alles kann man ohne jegliche Datenbankverbindung machen, die Daten bleiben also lokal im Speicher deines Programms.
    In Java ist das nicht möglich. Man kann solche Daten in speziellen Bäumen verwalten (B+ Bäume), die man dann allerdings selber implementieren muss. Eine solche Datenstruktur wird bei der Bereichssuche verwendet, die beispielsweise bei graphischen Algorithmen genutzt wird. Die Vorgehensweise ist dann folgendermaßen.
    Nehmen wir an, deine Daten sollen nach zwei Kriterien geordent sein, beispielsweise Geburtstag und Name. Auf Ebene 1 (dem Wurzelknoten) unterscheidest du dann nach Geburtstag, ob der Datensatz links oder rechts gespeichert werden soll. Auf Ebene 2 wird dann anhand des Namens unterschieden, ob der Datensatz nach links oder rechts soll. Auf Ebene 3 wird dann wieder per Geburtstag als Kriterium unterschieden etc. Der Comparator müsste also wissen, auf welcher Ebene des Baumes er aufgerufen wird, um das richtige Kriterium zu verwenden, was meines Erachtens nicht möglich ist. Ein TreeSet ist dafür ungeeignet.
    Du kannst aber, wie oben erwähnt, einem TreeSet über den Konstruktor einen speziellen Comparator zuweisen. der dann eine spezielle Compare-Methode in deinen Objekten aufruft (z.B. CompareBirthdayAndName(..) ), welche automatisch die richtigen Kriterien verwendet. Die TreeSets fungieren dann quasi als eigene Tabelle mit einem Comparator als einzigem Index. Für jedes TreeSet musst du dann einen eigenen Comparator schreiben und ein spezielle Compare-Funktion in deiner Objektklasse, welche dann von dem jeweiligen Comparator aufgerufen werden kann. Damit das auch sauber funktioniert, musst du zusätzlich für jeden Comparator (welcher jeweils einer eigenen Klasse angehören muss) ein eigenes Interface definieren, das dann von deinen zu sortierenden Objekten implementiert wird, damit diese dann auch von dem Comparator verwendet werden kann. Außerdem musst du als Datentyp für die TreeSets das Interface angeben das verwendet werden soll, nicht die Klasse der Objekte, die darin zu speichern sind. Zudem müssen alle betroffenen TreeSets neu sortiert werden, wenn die Objekte Änderungen in den Daten haben, die für ihre Sortierung relevant sind; eventuell solltest du dafür einen eigenen Event-Mechanismus implementieren. Welche Objekte nach welchem Kriterium sortiert werden sollen und welche nicht, entscheidest du dadurch, welchem TreeSet du sie zuweist.
    Alles in allem ist das ziemlich umständlich und aufwändig, aber ich sehe keine andere 'brauchbare' Möglichkeit, dein Problem in Java zu lösen.
    Geändert von Vereth (16.04.10 um 11:56 Uhr)
     
    Vielen Dank für die Nutzung des Bewerten- und Danke-Buttons

    Wenn man sieht, dass man einen anderen glücklich gemacht hat, ist die Welt um zwei glückliche Menschen reicher.

  10. #10
    gorefest gorefest ist offline Mitglied Brokat
    Registriert seit
    Apr 2009
    Beiträge
    256
    Hi,

    Du kannst einen Customcomparator bauen, der den jeweiligen Vergleich beherrscht. Umsortieren kannst Du dann mittels Collections.sort().

    Beispiel
    Code java:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    
        public static class MyComparator implements Comparator<SetType>, Serializable {
            public int compare(final SetType o1, final SetType o2) {
     
                return null;
            }
        }
     
    Gerufen wird der dann mittels
     
    Collections.sort(meinSet, new MyComparator());

    Wenn ich Dich richtig verstanden habe, geht es nur um die Klasse Person, die mehrfach auf unterschiedliche Weise verglichen werden soll, oder? Afaik ist das TreeSet ein sortiertes Set, dass die Reihenfolge nicht mehr ändert. Ein Collections.sort() sollte daher auch im Treeset greifen.



    Grüße
    gore
    Geändert von gorefest (16.04.10 um 11:45 Uhr)
     

Ähnliche Themen

  1. NoSuchElementException, TreeSet
    Von Steve222 im Forum Java Grundlagen
    Antworten: 2
    Letzter Beitrag: 21.01.10, 17:09
  2. Objekte in TreeSet einfügen + compareTo
    Von MaLb im Forum Algorithmen & Datenstrukturen mit Java
    Antworten: 2
    Letzter Beitrag: 02.06.09, 07:37
  3. Antworten: 3
    Letzter Beitrag: 02.04.08, 15:10
  4. Termine sortieren und im TreeSet speichern
    Von hollesepp im Forum Algorithmen & Datenstrukturen mit Java
    Antworten: 5
    Letzter Beitrag: 31.01.08, 15:56
  5. Statt HashSet die TreeSet verwenden
    Von lernen.2007 im Forum Java
    Antworten: 6
    Letzter Beitrag: 25.11.05, 01:40

Stichworte