Java将比较器与自定义比较器结合使用

时间:2018-05-21 18:41:10

标签: java sorting collections java-8 comparator

我想对以下示例列表进行排序,该列表当前仅包含具有自己的自定义规则的字符串。

ArrayList<String> coll = new ArrayList<>();
coll.add("just");
coll.add("sdsd");
coll.add("asb");
coll.add("b as");
coll.add("just");
coll.add("dhfga");
coll.add("jusht");
coll.add("ktsa");
coll.add("just");
coll.add("just");

我知道我可以为此编写自己的比较器,但是我知道Java也有比较器可以解决这个问题,我想知道如何使用Java API 组合的那些有我自己的。

应如何排序?

单词just应该始终是列表中出现的第一个单词,后面是按字母顺序排列的所有其他单词。

Comparator.naturalOrder()按字母顺序对列表进行排序,但是如何将这个comperator与自定义的comperator结合起来,以检查单词是just还是其他。

3 个答案:

答案 0 :(得分:6)

你可以这样做:

coll.sort(Comparator
    .comparingInt((String s) -> s.equals("just") ? 0 : 1) // Words "just" first
    .thenComparing(Comparator.naturalOrder())); // Then others

答案 1 :(得分:2)

您可以将标准集成到比较器中,如

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

或者您将操作分开,首先将所有出现的"just"移到前面,然后仅对其余元素进行排序:

int howManyJust = 0;
for(int ix = 0, num = coll.size(); ix < num; ix++)
    if(coll.get(ix).equals("just") && ++howManyJust <= ix)
        Collections.swap(coll, ix, howManyJust-1);

coll.subList(howManyJust, coll.size()).sort(Comparator.naturalOrder());

虽然这可能看起来更复杂,但它可能更有效,特别是对于较大的列表。

答案 2 :(得分:0)

第一步应该是定义自定义订单。我会通过使用Map来做到这一点。

Map<String, Integer> orderMap = new HashMap<>();
int order = 0;
for(String specialWord : yourListOfSpecialWords){
    orderMap.put(specialWord, order++);
}

现在使用该地图和自然顺序构建比较器作为备份:

Comparator<String> comparator = ((Comparator<String>) (o1, o2) -> {
    int leftScore = orderMap.getOrDefault(o1, Integer.MAX_VALUE);
    int rightScore = orderMap.getOrDefault(o2, Integer.MAX_VALUE);
    return Integer.compare(leftScore, rightScore);
}).thenComparing(String::compareTo);

使用此比较器对列表进行排序。注意:您可能只想将地图初始化一次,并将其保持在常量或至少在缓存中。

但是如果你的特殊情况只是一个单词,正如你的更新所暗示的那样,那么这当然是矫枉过正的,你应该在这里找到其中一个答案。