4

Ich versuche, einen Stream nach einer bestimmten Reihenfolge von einem seiner Felder zu sortieren.Sortieren Java Stream wie Schalter konditional

Jetzt erreiche ich dies, indem ich Streams in eine Liste umwandle und einen Schalter benutze und sie dann wieder in eine Liste in der gewünschten Reihenfolge bringe.

 

    fruits.forEach(fruit -> { 
       switch (fruit.getName()) { 
        case "Orange": 
         orangesList.add(fruit); 
         break; 
        case "Apple": 
         applesList.add(fruit); 
         break; 
        case "WaterMelon": 
         watermelonList.add(fruit); 
         break; 
        default: 
         otherFruits.add(fruit); 
         break; 
       } 
    }); 

    genericFruitList.addAll(0, orangeList); 
    genericFruitList.addAll(1, applesList); 
    genericFruitList.addAll(2, watermelonList); 
    genericFruitList.addAll(3, otherFruits); 

Ich frage mich, ob es irgendeine Änderung ist dies mit Strom sortierte Methode und mit einem benutzerdefinierten Komparator oder etwas ähnliches zu erreichen.

Vielen Dank im Voraus.

+4

'Collectors.groupingBy (Fruit :: getName)' würde die Früchte nach Namen gruppieren, wie im Schalter. Du könntest dann die 'addAll's so machen. –

+0

Erstellen einer Hilfsklasse kann Ihnen entsprechende Liste geben: fruitHelper.getList (fruit.getName) –

+3

Beachten Sie, dass Ihre aktuelle Logik seltsam ist. Nehmen wir an, Sie haben zwei von jeder Art von Frucht: Ihre resultierende 'genericFruitList' wäre orange, Apfel, Wassermelone, andere, andere, Wassermelone, Apfel, Orange. Soll der Einfügepunkt angegeben werden, oder möchten Sie sie am Ende hinzufügen? –

Antwort

6

Sie können einen Komparator erstellen wie eine explizite Ordnung mit

List<String> order = Arrays.asList("Orange", "Apple", "WaterMelon"); 
Comparator<String> comp 
    = Comparator.comparingInt(name -> order.indexOf(name)-Integer.MIN_VALUE); 

, die kann b e verwendet wie

List<Fruit> genericFruitList = fruits 
    .sorted(Comparator.comparing(fruit -> fruit.getName(), comp)) 
    .collect(Collectors.toList()); 

jedoch die gesamte Liste Sortierung, insbesondere mit einem List.indexOf basierten Komparator kann ineffizient ruhig sein. Eine Alternative wäre

List<Fruit> genericFruitList = fruits 
    .collect(Collectors.groupingBy(fruit -> fruit.getName())) 
    .entrySet().stream() 
    .sorted(Map.Entry.comparingByKey(comp)) 
    .flatMap(e -> e.getValue().stream()) 
    .collect(Collectors.toList()); 

sein, die nur einen Hash-Lookup pro Fruit und einzigen Art der eindeutigen Zuordnungen durchführt. Dies kann als eine Variante von Bucket Sort angesehen werden.

+0

Vielen Dank. Das hat perfekt für mich funktioniert :) – Antonio682

5

Wenn Sie die Frucht in einer bestimmten Reihenfolge (Orangen zuerst, dann Äpfel, dann Wassermelone, dann „andere“) sortieren möchten, können Sie damit einen Komparator definieren:

List<String> order = Arrays.asList("Orange", "Apple", "Watermelon"); 
Comparator<Fruit> comparator = Comparator.comparing(f -> { 
    int i = order.indexOf(f.getName()); 
    return (i >= 0) ? i : order.size(); 
}); 

und dann sort:

List<Fruit> genericFruitList = fruits.stream().sorted(comparator).collect(Collectors.toList()); 
+0

BTW Guave hat 'Ordering.explicit (Liste )' das könnte auch hier verwendet werden. – Eugene

+1

@Eugene ["Wenn Sie Java 8 verwenden, ist diese Klasse jetzt veraltet"] (https://google.github.io/guava/releases/23.0/api/docs/com/google/common/collect/Ordering. html). Darüber hinaus behandelt das nicht "andere" Werte. –