我试图通过其中一个字段按特定顺序对流进行排序。
现在我通过将流转换为列表并使用开关然后将它们重新加入到所需顺序的列表中来实现此目的。
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);
我想知道是否有使用流排序方法实现此目的的任何更改 并使用自定义比较器或类似的东西。
提前致谢。
答案 0 :(得分:6)
您可以使用显式顺序(如
)创建比较器List<String> order = Arrays.asList("Orange", "Apple", "WaterMelon");
Comparator<String> comp
= Comparator.comparingInt(name -> order.indexOf(name)-Integer.MIN_VALUE);
可以像
一样使用List<Fruit> genericFruitList = fruits
.sorted(Comparator.comparing(fruit -> fruit.getName(), comp))
.collect(Collectors.toList());
然而,对整个列表进行排序,尤其是基于List.indexOf
的比较器,可能会非常低效。另一种选择是
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());
只执行每Fruit
的哈希查找,只对不同的映射进行排序。
这可以看作是Bucket Sort的变体。
答案 1 :(得分:5)
如果你想把水果分成特定的顺序(首先是橙子,然后是苹果,然后是西瓜,然后是“其他”),你可以定义一个比较器:
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();
});
然后排序:
List<Fruit> genericFruitList = fruits.stream().sorted(comparator).collect(Collectors.toList());