はじめに
以下のような Item
を top
-> middle
-> bottom
の順序でソートしたい。
List<Item> list = Arrays.asList( new Item(1, "bottom"), new Item(2, "top"), new Item(3, "middle"), new Item(4, "top"));
第2ソートキーを id とすると、Guava では ComparisonChain で Ordering.explicit()
を指定することとなる。
ComparisonChain.start() .compare(o1.getName(), o2.getName(), Ordering.explicit(priorities).nullsLast()) .compare(o1.getId(), o2.getId(), Ordering.natural().nullsLast()) .result();
Java8 Stream での任意順序ソート
Java8 Stream では、Ordering.explicit()
に相当するものは無いので、以下のようにする。
List<String> priorities = Arrays.asList("top", "middle", "bottom"); List<Item> sorted = list.stream() .sorted(Comparator .comparing((Item item) -> priorities.indexOf(item.getName())) .thenComparing(Item::getId)) .collect(Collectors.toList());
以下のように並び替えることができる。
Item {2, 'top'}, Item {4, 'top'}, Item {3, 'middle'}, Item {1, 'bottom'}
未知のキーを末尾に持ってくる
前述のソートだと、new Item(5, "?")
であったり new Item(6, null)
のような、未知キーが先頭にきてしまう。
その場合は、逆順でソートした方がよい。
List<String> priorities = Arrays.asList("top", "middle", "bottom"); Collections.reverse(priorities); List<Item> sorted = list.stream() .sorted(Comparator .comparing((Item item) -> priorities.indexOf(item.getName()), Comparator.reverseOrder()) .thenComparing(Item::getId)) .collect(Collectors.toList());
以下のような並びになる。
Item {2, 'top'}, Item {4, 'top'}, Item {3, 'middle'}, Item {1, 'bottom'}, Item {5, '?'}, Item {6, null}