HashSet mit Comparable sortieren

jerevat

Mitglied
Hallo,

gegeben ist ein HashSet<String> dessen Strings wie folgt aussehen: "stringValue_longValue".
Anhand der longValue soll das HashSet sortiert werden.
Also dachte ich mir eine erweiterte HashSet-Klasse mit der Schnittstelle Comparable zu entwickeln:
Java:
public class HashSetEx extends HashSet<String> implements Comparable<Long>
Was mich dabei verwirrt, ist, was kann ich hier womit vergleichen, wenn mir doch nur this.toString() zur Verfügung steht?
Das this.toString ist nicht einfach nur ein Element, sondern eine Art Array.
Ist das überhaupt der richtige Ansatz für mein Vorhaben?
 
Beste Antwort
Ich versuche mal B, die Stream.sort() Funktion anzuwenden.
Das einfach einmal schnell aufgebaut, wie das dann mit dem sorted(Comparator) aussehen könnte:
Java:
import java.util.Comparator;
import java.util.HashSet;

public class Main {
    public static void main(String[] args) {
        HashSet<String> myHashSet = new HashSet<>();
        myHashSet.add("a_5");
        myHashSet.add("b_1");
        myHashSet.add("c_7");
        myHashSet.add("d_2");

        myHashSet.stream()
                .sorted(Comparator.comparingLong(s -> getLongValue(s)))
                .forEach(System.out::println);
    }

    public static long getLongValue(String value) {
        String[] splited = value.split("_");
        return...
You make my day ... !

Eine Sortierung von HashSet ist nicht möglich. Die Elemente des HashSet können jedoch indirekt sortiert werden, indem sie in List oder TreeSet umgewandelt werden, aber dadurch bleiben die Elemente im Zieltyp statt im HashSet-Typ.
 
Da erst einmal ein paar wichtige Grundlagen:

a) Was genau willst Du sortieren? Und dann sind die ja Strings, die in einem bestimmten Format sind. Daher ist es ein Comparable<String> bzw. ein Comparator<String>, den Du implementieren willst.

b) Ein HashSet ist nicht sortiert. Aber Du kannst natürlich de Elemente eines HashSet sortieren. Das ginge z.B. per Stream - also myHashSet.stream().sort(comparator).... - Am Ende kannst Du es in eine List bringen oder so.
Aber wenn die Elemente generell sortiert sein sollen, dann ist der gewählte Datentyp evtl. falsch. Vielleicht willst du statt einer HashSet eine TreeSet haben? Dann kannst Du einen Comparator mit festlegen und Du hast die Elemente immer sortiert.

c) Wähle vernünftige Datentypen! Deine Strings haben ja ganz offensichtlich einen bestimmten Inhalt: Einen String Anteil und einen long Anteil. Da würde es also Sinn machen, das auch entsprechend in einer entsprechenden Klasse zu speichern (Einfach mal quick & dirty etwas zusammen geschrieben. Fehlerbehandlung ist noch nicht super, aber es zeigt, worauf ich hinaus will:
Java:
import org.jetbrains.annotations.NotNull;

import java.util.Comparator;

public class MyDataType implements Comparable<MyDataType> {
    private String stringPart;
    private long longPart;

    public MyDataType(String stringPart, long longPart) {
        this.stringPart = stringPart;
        this.longPart = longPart;
    }

    public MyDataType() {
    }

    public String getStringPart() {
        return stringPart;
    }

    public void setStringPart(String stringPart) {
        this.stringPart = stringPart;
    }

    public long getLongPart() {
        return longPart;
    }

    public void setLongPart(long longPart) {
        this.longPart = longPart;
    }

    @Override
    public String toString() {
        return stringPart + "_" + longPart;
    }
    
    public static MyDataType fromString(String string) {
        if (string == null || !string.contains("_"))
            throw new RuntimeException("Not a valid string!");
        
        String[] parts = string.split("_");
        return new MyDataType(parts[0], Long.parseLong(parts[1]));
    }

    @Override
    public int compareTo(@NotNull MyDataType other) {
        return Long.compare(longPart, other.longPart);
    }
}

Das wäre dann etwas, das in einem TreeSet mit der natural Order wie gewünscht sortiert wäre.
 
You make my day ... !

Eine Sortierung von HashSet ist nicht möglich. Die Elemente des HashSet können jedoch indirekt sortiert werden, indem sie in List oder TreeSet umgewandelt werden, aber dadurch bleiben die Elemente im Zieltyp statt im HashSet-Typ.
Eine Liste oder ein TreeSet() sortieren nach dem Alphabet oder nach einem Zahlenwert, je nach Inhalt.
Bei mir besteht der String aus einem Text, einem Unterstrich als Trenner / Separator und einem long-Zahlenwert (= Datum in Millisekunden):
Java:
stringVar = "abc_12345678910111213"
Ich möchte diese HashSet-Strings splitten, nach dem Datumswert sortieren und diese Änderung im HashSet so übernehmen
 
b) Ein HashSet ist nicht sortiert. Aber Du kannst natürlich de Elemente eines HashSet sortieren. Das ginge z.B. per Stream - also myHashSet.stream().sort(comparator).... - Am Ende kannst Du es in eine List bringen oder so.
Aber wenn die Elemente generell sortiert sein sollen, dann ist der gewählte Datentyp evtl. falsch. Vielleicht willst du statt einer HashSet eine TreeSet haben? Dann kannst Du einen Comparator mit festlegen und Du hast die Elemente immer sortiert.

c) Wähle vernünftige Datentypen! Deine Strings haben ja ganz offensichtlich einen bestimmten Inhalt: Einen String Anteil und einen long Anteil. Da würde es also Sinn machen, das auch entsprechend in einer entsprechenden Klasse zu speichern (Einfach mal quick & dirty etwas zusammen geschrieben. Fehlerbehandlung ist noch nicht super, aber es zeigt, worauf ich hinaus will
Ich versuche mal B, die Stream.sort() Funktion anzuwenden.
Ansonsten wird es wohl auf C, einen "eigenen Datentypen" hinauslaufen.
 
Ich versuche mal B, die Stream.sort() Funktion anzuwenden.
Das einfach einmal schnell aufgebaut, wie das dann mit dem sorted(Comparator) aussehen könnte:
Java:
import java.util.Comparator;
import java.util.HashSet;

public class Main {
    public static void main(String[] args) {
        HashSet<String> myHashSet = new HashSet<>();
        myHashSet.add("a_5");
        myHashSet.add("b_1");
        myHashSet.add("c_7");
        myHashSet.add("d_2");

        myHashSet.stream()
                .sorted(Comparator.comparingLong(s -> getLongValue(s)))
                .forEach(System.out::println);
    }

    public static long getLongValue(String value) {
        String[] splited = value.split("_");
        return Long.parseLong(splited[1]);
    }
}
 
Beste Antwort
Eine Liste oder ein TreeSet() sortieren nach dem Alphabet oder nach einem Zahlenwert, je nach Inhalt.
Bei mir besteht der String aus einem Text, einem Unterstrich als Trenner / Separator und einem long-Zahlenwert (= Datum in Millisekunden):
Java:
stringVar = "abc_12345678910111213"
Ich möchte diese HashSet-Strings splitten, nach dem Datumswert sortieren und diese Änderung im HashSet so übernehmen
TreeSet können beliebig sortieren, je nachdem was du zum Vergleichen benutzt, und List kann man natürlich auch beliebig sortieren - und anders als bei HashSets ist es bei den beiden überhaupt möglich, diese zu sortieren. Ein HashSet ist immer ungeordnet!
 
Eine Liste oder ein TreeSet() sortieren nach dem Alphabet oder nach einem Zahlenwert, je nach Inhalt.
Bei mir besteht der String aus einem Text, einem Unterstrich als Trenner / Separator und einem long-Zahlenwert (= Datum in Millisekunden):
Java:
stringVar = "abc_12345678910111213"
Ich möchte diese HashSet-Strings splitten, nach dem Datumswert sortieren und diese Änderung im HashSet so übernehmen
Der Punkt ist: Warum ist der String so aufgebaut? Machst du das selbst? Man könnte eine Klasse verwenden, welche den String– und long–Wert getrennt verwaltet. Dann wäre so etwas sehr leicht zu handhaben.
 
Das einfach einmal schnell aufgebaut, wie das dann mit dem sorted(Comparator) aussehen könnte:
Fast gleich:

Java:
final String ID_SEPARATOR = "_";
Set<String> _channelIdList = new HashSet<>();

private void sortChannelIds() {
    _channelIdList = _channelIdList.parallelStream()
    .sorted(Comparator.comparingLong(this::getMilliseconds))
    .collect(Collectors.toCollection(LinkedHashSet::new));
}

private long getMilliseconds(String value) {
    return Long.valueOf(value.split(ID_SEPARATOR)[5]);
}

Es sortiert auf jeden Fall richtig.
 
TreeSet können beliebig sortieren, je nachdem was du zum Vergleichen benutzt, und List kann man natürlich auch beliebig sortieren - und anders als bei HashSets ist es bei den beiden überhaupt möglich, diese zu sortieren. Ein HashSet ist immer ungeordnet!
Ich kann auf das (Hash)Set nicht verzichten, da ich diese Struktur zum Speichern von Daten mittels SharedPreferences() in Android benötige.
 
Ich kann auf das (Hash)Set nicht verzichten, da ich diese Struktur zum Speichern von Daten mittels SharedPreferences() in Android benötige.
Kannst Du das evtl. etwas erläutern? Du bekommst also bereits ein HashSet von einer Android Methode? Wenn Du nur generell ein Set brauchst: TreeSet ist auch ein Set! Nur eben im Gegensatz zu dem HashSet hast Du bei dem TreeSet noch zusätzlich die Sortierung.
 
Kannst Du das evtl. etwas erläutern? Du bekommst also bereits ein HashSet von einer Android Methode?
Für die Android-Benachrichtigungen generiere ich entsprechende Channel-Ids, die aus kurzen Texten und Zahlen - durch einen Separator getrennt - zusammengesetzt sind.
Diese IDs kommen in die HashSet<String> Auflistung, weil sich Objekte dieser Klasse mittels SharedPreferences() speichern und laden lassen.
Da die Anzahl der IDs überschaubar ist, bin ich auf eine lokale Datenbank nicht angewiesen und kann diese Auflistung gemeinsam mit den Einstellungswerten der App in eine XML hinterlegen.
Bevor ich die Frage hier gestellt habe, habe ich mit der TreeSet-Klasse herumprobiert.
Damit konnte ich zwar neue IDs in jenen Moment richtig ordnen, die vorherigen haben sich jedoch nicht angesprochen gefühlt und blieben am Ende gelistet.
Weil das nicht ganz zielführend war, wollte ich eine eigene Set-Klasse mit einer Sortierfunktion, die noch mehr Fragen aufwarf. Und so landete ich hier.
 
Dann sollte es aus meiner Sicht kein Problem sein, das HashSet durch ein TreeSet zu ersetzen. Dann hättest Du die Sortierung in der Datenstruktur mit drin.
 
Dann sollte es aus meiner Sicht kein Problem sein, das HashSet durch ein TreeSet zu ersetzen. Dann hättest Du die Sortierung in der Datenstruktur mit drin.
So geht es auch:
Java:
final String ID_SEPARATOR = "_";

Set<String> _channelIdList = new TreeSet<>((o1, o2) -> {
    Long l1 = Long.valueOf(o1.split(ID_SEPARATOR)[5]);
    Long l2 = Long.valueOf(o2.split(ID_SEPARATOR)[5]);
    return l1.compareTo(l2);
});
Im Anschluss das Set mit Daten / Strings füllen und alles wird automatisch (von klein nach groß) sortiert.
 

Zurück
Oben