按特定字符排序列表(Java 8)

hec*_* s. 5 java sorting list comparator java-8

我有以下列表:

List<String> fruits = new ArrayList<String>(Arrays.asList("Apple", "Banana", "Orange", "Watermelon", "Peach")); 
Run Code Online (Sandbox Code Playgroud)

我需要在这个条件下订购它:

  1. 首先,包含char"o"或"O"的那些
  2. 然后,其余的.

结果应该是:

Orange, Watermelon, Apple, Banana, Peach
Run Code Online (Sandbox Code Playgroud)

我怎么能用Java 8做到这一点?

Pet*_*rey 13

您可以使用比较器链.

List<String> fruits = new ArrayList<>(Arrays.asList(
                               "Apple", "Banana", "Orange", "Watermelon", "Peach"));
fruits.sort(Comparator.comparing((String s) -> !s.contains("O") && !s.contains("o"))
        .thenComparing(Comparator.naturalOrder()));
System.out.println(fruits.stream().collect(Collectors.joining(", ")));
Run Code Online (Sandbox Code Playgroud)

第一个比较器查看字符串是否包含O,使得首先执行的操作,第二个比较器使用自然顺序.

注意:Boolean.TRUE.compareTo(Boolean.FALSE) > 0所以为了使包含O的字符串先进行,我将其翻转为!

这打印

Orange, Watermelon, Apple, Banana, Peach
Run Code Online (Sandbox Code Playgroud)

注意:在这种情况下,new ArrayList<>( ... )不需要,因为sort不会更改元素的数量,只需重新排列它们.


编辑:基于@Holger的建议.

如果优选稳定的排序,即尽可能保持订单.

List<String> fruits = Arrays.asList(
        "Watermelon", "Peach", "Orange", "Banana", "Apple");
fruits.sort(Comparator.comparing((String s) -> !s.contains("O") && !s.contains("o")));
System.out.println(fruits.stream().collect(Collectors.joining(", ")));
Run Code Online (Sandbox Code Playgroud)

版画

Watermelon, Orange, Peach, Banana, Apple
Run Code Online (Sandbox Code Playgroud)

  • 据我所知,没有要求"其余部分"按问题中的自然顺序排序.所以你可以简单地使用`Comparator.comparing(s - >!s.toUpperCase().contains("O"))`来将那些带有O的东西移到前面并按原样保持它们的相对顺序.另一种选择是`fruits.sort(Comparator.comparing(Pattern.compile("(?i)o").asPredicate().negate():: test));`它避免为每个字符串创建所有字符串的大写副本比较.这可以为更大的列表和/或更大的字符串付出代价. (4认同)
  • `Pattern`仅为整个操作编译一次.当然,如果你多次执行这个操作,你可以考虑保留模式,但这也适用于整个`Comparator`.您也可以使用`Pattern.compile("o",Pattern.CASE_INSENSITIVE)来降低模式初始化的成本.但无论如何,对于这样一个微不足道的模式,准备并不比复制字符串更昂贵,而另一个比较器每次比较做两次(并且在最坏的情况下有大约n×log n比较)...... (2认同)