最后排序一个元素

时间:2019-03-11 13:26:44

标签: java sorting java-8 java-stream

我有一个对象列表,我想按一个属性按字母顺序对其进行排序。但是,如果此属性匹配特定的字符串,我想添加一个例外规则。例如:

public class Car {
  String name;
}
List<Car> cars = asList(
    new Car("Unassigned"), 
    new Car("Nissan"), 
    new Car("Yamaha"), 
    new Car("Honda"));

List<Car> sortedCars = cars
  .stream
  .sorted(Comparator.comparing(Car::getName))
  .collect(Collectors.toList());

如果cars.name == "Unassigned",那么这辆车应该留在列表的末尾,其结果将是:

[Car<Honda>, Car<Nissan>, Car<Yamaha>, Car<Unassigned>]

5 个答案:

答案 0 :(得分:15)

  List<Car> sortedCars = cars
        .stream()
        .sorted(Comparator.comparing(
            Car::getName,
            Comparator.comparing((String x) -> x.equals("Unassigned"))
                      .thenComparing(Comparator.naturalOrder())))
        .collect(Collectors.toList());

这里发生了很多事情。首先,我正在使用Comparator.comparing(Function, Comparator);然后是(String x) -> x.equals("Unassigned"),它实际上是对Boolean(即Comparable)进行比较的;那么使用(String x)的事实-作为这种类型的见证人,就可以正确地推断类型...

答案 1 :(得分:8)

最直接,最易读的解决方案可能是编写一个实现您的排序逻辑的自定义比较器。

尽管如此,您仍然可以使用Comparator.comparing方法来使它变得更加清晰:

public static final String UNASSIGNED = "Unassigned";

List<Car> cars = List.of(
    new Car("Unassigned"), 
    new Car("Nissan"), 
    new Car("Yamaha"), 
    new Car("Honda"));

List<Car> sortedCars = cars.stream()
    .sorted(Comparator.comparing(Car::getName, (name1, name2) -> {
            if (name1.equals(name2)) return 0;
            if (name1.equals(UNASSIGNED)) return 1;
            if (name2.equals(UNASSIGNED)) return -1;
            return name1.compareTo(name2);
    }))
    .collect(Collectors.toList());

此外,将命名常量用于"Unassigned"之类的特殊值也是一种很好的样式。


此外,请注意,如果您不需要保留未排序的cars列表,则可以对该列表进行排序而不是使用流:

cars.sort(UNASSIGNED_COMPARATOR);

答案 2 :(得分:1)

一种可能的方法是使用分区方式:

Map<Boolean, List<Car>> partitionedCars = cars
        .stream()
        .collect(Collectors.partitioningBy(a -> a.getName().equals("Unassigned")));

List<Car> sortedCars = Stream.concat(partitionedCars.get(Boolean.FALSE).stream()
        .sorted(Comparator.comparing(Car::getName)), partitionedCars.get(Boolean.TRUE).stream())
        .collect(Collectors.toList());

答案 3 :(得分:0)

您可以在比较器中用字母结尾字符串替换“未指定”。

Comparator.comparing(car -> car.getName().equals("Unassigned") ? "ZZZ" : car.getName())

答案 4 :(得分:0)

或者,只需删除所有“未分配”的实例,然后在List的末尾添加许多实例。例如:

int numberOfUnassigned = 0;
for (Iterator<Car> iterator = sortedCars.iterator(); iterator.hasNext();) {
    String str = iterator.next().getName();
    if (str.equals("Unassigned")) {
        iterator.remove();
        numberOfUnassigned++;
    }
}

然后将numberOfUnassigned的数字添加到末尾。