将列表按字母顺序排序,并将特定值放在开头(如果存在)

5
我正在寻找一种最易读的比较器定义,满足以下测试用例:
@Test
public void testComparator() {
    List<String> toSort = Lists.newArrayList("a", "b", "c", "d", "e", "f");
    Collections.shuffle(toSort);
    Comparator<String> theSolution = ???; 
    Collections.sort(toSort, theSolution);
    System.out.println(toSort); // Prints [c, a, b, d, e, f]
}

我尝试使用Guava的Ordering定义一个比较器,如下所示:
Ordering.explicit("c").thenComparing(Ordering.natural());

然而,明确的枚举对于未枚举项会抛出异常。因此,该解决方案失败了。有什么建议吗?
4个回答

4

您可以明确编写一个比较函数,例如:

Comparator<String> theSolution = Comparator.comparing(a -> a.equals("c") ? "" : a);
// treat "c" as the same as the empty string "" when sorting which will be ranked first.

1
仅当数组中没有空字符串时才起作用。 - shmosel

3

从您提供的示例中不清楚是否希望保留非“c”成员的当前顺序还是按字母顺序排序。如果要将“c”放在最前面并保留其余成员,则可以使用以下方法:

Comparator.comparing("c"::equals).reversed();

需要对比器进行反转,因为布尔类型的自然排序是先false后true。

将剩余项按字母顺序排序可以通过以下方式实现:

Comparator.comparing("c"::equals).reversed()
    .thenComparing(Object::toString, String::compareTo);

对于次要排序,您可以使用.thenComparing(Comparator.naturalOrder()).thenComparing(String::compareTo) - shmosel
@shmosel 我不这么认为。在那一点上,Erasure 的类型是 Comparator<Object> 而不是 Comparator<String> - sprinter
这是不幸的事实。你可以通过执行 Comparator.comparing((String s) -> s.equals("c")) 或者 Comparator.<String, Boolean>comparing("c"::equals) 来修复它,但我不会声称这两个选项中的任何一个都是更好的选择。 - shmosel

1

既然你正在使用Guava,这里提供了一种使用ComparisonChain的解决方案。我喜欢他们在布尔运算优先级方面非常明确:

Comparator<String> theSolution = (a, b) -> ComparisonChain.start()
        .compareTrueFirst(a.equals("c"), b.equals("c"))
        .compare(a, b)
        .result();

0

你可以使用比较器链来组合这些任务,例如:

List<String> toSort = Arrays.asList("a", "b", "c", "d", "e", "f");
Collections.shuffle(toSort);

toSort.sort(Comparator.comparing((String s) -> !s.equals("c"))
                      .thenComparing(Comparator.naturalOrder()));

System.out.println(toSort); // Prints [c, a, b, d, e, f]

但你也可以考虑将这两个任务分开处理,先进行排序,然后再将所需的值移动到前面:

List<String> toSort = Arrays.asList("a", "b", "c", "d", "e", "f");
Collections.shuffle(toSort);

toSort.sort(null);// null implies natural order
final int ix = toSort.indexOf("c");
if(ix>=0)
    Collections.rotate(toSort.subList(0, toSort.lastIndexOf("c")+1), -ix);

System.out.println(toSort); // Prints [c, a, b, d, e, f]

这也适用于多个出现。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接