在末尾使用一个元素进行排序

2022-09-02 20:40:06

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

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>]

答案 1
  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")BooleanComparable(String x)


答案 2

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

不过,您仍然可以使用该方法使其更漂亮一些: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(toList());

可以将“末端”功能提取到单独的可比较组合器方法中。喜欢这个:

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

public static <T extends Comparable<T>> Comparator<T> withValueAtEnd(T atEnd) {
  return withValueAtEnd(atEnd, Comparator.naturalOrder());
}

public static <T> Comparator<T> withValueAtEnd(T atEnd, Comparator<T> c) {
    return (a, b) -> {
        if (a.equals(atEnd)) return 1;
        if (b.equals(atEnd)) return -1;
        return c.compare(a, b);
    };
}

此外,对特殊值(如 ."Unassigned"


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

cars.sort(UNASSIGNED_COMPARATOR);

推荐