我对字符串的默认比较器(在 SortedSet 中)有疑问。问题是默认比较器不会对包含数字的良好字符串进行排序,即:在集合中我有:
room1, room2, room100
自然排序应该像上面一样,但在集合中我有:
room1, room100, room2
我知道为什么会这样,但我不知道如何改变它。
试试这个比较器,它会删除所有非数字字符,然后将剩余的字符作为数字进行比较:
Collections.sort(strings, new Comparator<String>() {
public int compare(String o1, String o2) {
return extractInt(o1) - extractInt(o2);
}
int extractInt(String s) {
String num = s.replaceAll("\\D", "");
// return 0 if no digits found
return num.isEmpty() ? 0 : Integer.parseInt(num);
}
});
这是一个测试:
public static void main(String[] args) throws IOException {
List<String> strings = Arrays.asList("room1.2", "foo1.1", "foo", "room2.3", "room100.999", "room10", "room.3");
Collections.sort(strings, new Comparator<String>() {
public int compare(String o1, String o2) {
return extractInt(o1) - extractInt(o2);
}
int extractInt(String s) {
String num = s.replaceAll("\\D", "");
// return 0 if no digits found
return num.isEmpty() ? 0 : Integer.parseInt(num);
}
});
System.out.println(strings);
}
输出:
[foo, room1, room2, room10, room100]
当数字是小数时(也展示了 Java 8+ 风格):
public static void main(String[] args) {
List<String> strings = Arrays.asList("room1.2", "foo1.1", "room2.3", "room100.999", "room10", "room.3");
Collections.sort(strings, Comparator.comparing(Application::extractDouble));
System.out.println(strings);
}
static double extractDouble(String s) {
String num = s.replaceAll("[^\\d.]", "");
// return 0 if no digits found
return num.isEmpty() ? 0 : Double.parseDouble(num);
}
结果:
[foo, room.3, foo1.1, room1.2, room2.3, room10, room100.999]
使用@bohemian 答案。只是改善了一点。这对我很有用..
Collections.sort(asdf, new Comparator<String>() {
public int compare(String o1, String o2) {
String o1StringPart = o1.replaceAll("\\d", "");
String o2StringPart = o2.replaceAll("\\d", "");
if(o1StringPart.equalsIgnoreCase(o2StringPart))
{
return extractInt(o1) - extractInt(o2);
}
return o1.compareTo(o2);
}
int extractInt(String s) {
String num = s.replaceAll("\\D", "");
// return 0 if no digits found
return num.isEmpty() ? 0 : Integer.parseInt(num);
}
});
试试这个。我假设你的字符串开头总是有“房间”。
List<String> list = Arrays.asList("room1", "room100", "room2");
Collections.sort(list, new Comparator<String>()
{
@Override
public int compare(String o1, String o2)
{
return new Integer(o1.replaceAll("room", ""))
.compareTo(new Integer(o2.replaceAll("room", "")));
}
});
这是我Comparator
对这种排序的实现:(字符串可以从任何字符开始)
public class StringNumberComparator implements Comparator<String>{
@Override
public int compare(String o1, String o2) {
int i1 = this.getRearInt(o1);
int i2 = getLeadingInt(o2);
String s1 = getTrailingString(o1);
String s2 = getTrailingString(o2);
if(i1==i2)
return s1.compareTo(s2);
if(i1>i2)
return 1;
else if(i1<i2)
return -1;
return 0;
}
private int getRearInt(String s) {
s=s.trim();
int i=Integer.MAX_VALUE;
try {
i = Integer.parseInt(s.split("[^0-9]+")[1]);
} catch(ArrayIndexOutOfBoundsException e) {
} catch(NumberFormatException f) {
return i;
}
return i;
}
private String getTrailingString(String s) {
return s.replaceFirst("[0-9]", "");
}
}
您可以实现一个比较器并将其传递给 set 构造函数。请参阅http://docs.oracle.com/javase/1.4.2/docs/api/java/util/Comparator.html。
如果您所有的字符串都采用 room[number] 的形式,您可以剥离“room”解析数字并进行比较。
或者 - 您可以将整数存储在您的设置中并使用“房间”前缀打印它们。
一个懒惰的选择是让字符串比较器工作而不做任何额外的事情(定义你自己的比较器)。您可以通过用零填充字符串中的数字来实现这一点:room0001, room0002, room0100
然后默认的字符串比较器将起作用。但是,您确实需要知道最大数值,以便您可以相应地调整填充。