既然我主张重新打开它,这里有一个 Comparator<String> 可以满足您的需求:
package testJ;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
public class WeirdOrderComparator implements Comparator<String> {
private static List<String> COMPASS_ORDER = Arrays.asList("E:S:W:N"
.split(":"));
private static List<String> D_ORDER = Arrays.asList("W:G:R".split(":"));
private static List<String> SUFFIX_ORDER = Arrays.asList("m:p:s::d"
.split(":"));
private int indexFor(String target, List<String> order) {
int r = order.indexOf(target);
if (r < 0) {
return order.size();
} else {
return r;
}
}
private int getSuffixNumber(String s) {
switch (s.length()) {
case 1:
return indexFor("", SUFFIX_ORDER);
case 2:
return indexFor(s.substring(1), SUFFIX_ORDER);
default:
return 99;
}
}
private int getWithinGroupNumber(int suffixGroup, String s) {
switch (suffixGroup) {
case 0:
case 1:
case 2:
return Integer.valueOf(s.substring(0, s.length() - 1));
case 3:
return indexFor(s, COMPASS_ORDER);
case 4:
return indexFor(s.substring(0, 1), D_ORDER);
default:
return 99;
}
}
public int compare(String o1, String o2) {
int sfx1 = getSuffixNumber(o1);
int sfx2 = getSuffixNumber(o2);
if (sfx1 != sfx2) {
return sfx1 - sfx2;
}
int grp1 = getWithinGroupNumber(sfx1, o1);
int grp2 = getWithinGroupNumber(sfx2, o2);
if (grp1 != grp2) {
return grp1 - grp2;
}
return o1.compareTo(o2);
}
}
它可以用作:
package testJ;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class WeirdOrderTest {
public static void main(String args[]) {
List<String> testList = Arrays.asList("N 2p 9s 9s 1p 9m N 4s 1m 5p 7m 2s 5s 5m".split(" "));
System.out.println("Original order: " + testList);
ArrayList<String> sorted = new ArrayList<String>();
sorted.addAll(testList);
Collections.sort(sorted, new WeirdOrderComparator());
System.out.println("Sorted: " + sorted);
}
}
这会产生:
Original order: [N, 2p, 9s, 9s, 1p, 9m, N, 4s, 1m, 5p, 7m, 2s, 5s, 5m]
Sorted: [1m, 5m, 7m, 9m, 1p, 2p, 5p, 2s, 4s, 5s, 9s, 9s, N, N]
这里的一般策略是:
找到一个可以区分两个字符串的规则。在这种情况下,我首先确定字符串的一般“组”:以“m”、“p”、“s”结尾的东西、单个字母或以“d”结尾的东西。
如果该规则区分两个输入,则返回一个数字,如果 o1 应该先出现,则返回负数,如果 o1 应该后出现,则返回正数。要记住这个约定,请考虑“如果o1 和o2 是小整数,就像o1 - o2”(忽略溢出)。
如果该规则无法区分o1 和o2,则查找其他规则等。
最后,如果你的规则用完了,返回 0 或委托其他比较。
请记住,您的 Comparator 应该合理地处理您不期望的字符串 - 它可能会抛出异常(如果给它“Xs”,则会抛出异常),但如果它不抛出异常那么结果应该是一致的。也就是说,如果compare(x, y) < 0 和compare(y, z) < 0 则如果compare(x, z) 没有抛出异常,则compare(x, z) 必须为负数,而不管x、y 和z 是什么。确保这一点的一种方法是按照我在此处所做的方式构建您的比较器,在其中我为每个字符串找到一系列“订单号”,然后如果订单号没有帮助,则委托给 String.compareTo。