优化比较器的方法
Way to optimize comparator
有没有比这更有效的方法来按姓氏 1 排序人名,如果不是,则按姓氏 2,如果不是,则按姓名?
这太慢了,谢谢!
Collections.sort(lResult, new java.util.Comparator<Map>() {
public int compare(Map m1, Map m2) {
int lResult;
String i1= (String)m1.get("surname1");
String i2= (String)m2.get("surname1");
if((i1 == null) || (i2==null)) {lResult = 0;}
else {lResult = i1.compareTo(i2);}
if (lResult == 0) {
String t1= (String)m1.get("surname2");
String t2= (String)m2.get("surname2");
if((t1 == null) || (t2==null)) {lResult = 0;}
else {lResult = t1.compareTo(t2);}
}
if (lResult == 0) {
String x1= (String)m1.get("name");
String x2= (String)m2.get("name ");
if((x1 == null) || (x2==null)) {lResult = 0;}
else {lResult = x1.compareTo(x2);}
}
return lResult;
}
});
无论速度如何,您的比较器都不正确。
唯一应该被认为是平等的东西,呃,平等的东西。您当前会认为 null
等于 "non-null"
,因此这会导致奇怪的行为。
具体来说,您似乎在比较第一对对应的值,它们都是 non-null。这违反了 Comparator 实现的传递性要求。考虑一下,例如:
A = {"surname1": "A", "surname2", null, "name": "A"}
B = {"surname1": null, "surname2", "B", "name": "B"}
C = {"surname1": "A", "surname2", "C", "name": null}
根据您的比较器,A < B
和 B < C
。然而,A == C
,因此使它成为一个无效的比较器。
正确地编写此比较器的最简单方法如下:
nullsLast(comparing(m -> (String) m.get("surname1")))
.thenComparing(nullsLast(comparing(m -> (String) m.get("surname2"))))
.thenComparing(nullsLast(comparing(m -> (String) m.get("name"))));
其中 nullsLast
和 comparing
是来自 Comparator
的方法。 (可以使用 nullsFirst
来代替,如果您更愿意这样处理空值的话)。
对于pre-Java8,你可以使用辅助方法写一个等价的比较:
public int compare(Map m1, Map m2) {
int lResult;
lResult = compare(m1, m2, "surname1");
if (lResult != 0) return lResult;
lResult = compare(m1, m2, "surname2");
if (lResult != 0) return lResult;
return compare(m1, m2, "name");
}
private int compare(Map m1, Map m2, String key) {
String v1= (String)m1.get(key);
String v2= (String)m2.get(key);
if (v1 != null && v2 != null) {
return v1.compareTo(v2);
}
return Boolean.compare(v1 != null, v2 != null);
}
或者使用类似 Guava 的 ComparisonChain
。
有没有比这更有效的方法来按姓氏 1 排序人名,如果不是,则按姓氏 2,如果不是,则按姓名? 这太慢了,谢谢!
Collections.sort(lResult, new java.util.Comparator<Map>() {
public int compare(Map m1, Map m2) {
int lResult;
String i1= (String)m1.get("surname1");
String i2= (String)m2.get("surname1");
if((i1 == null) || (i2==null)) {lResult = 0;}
else {lResult = i1.compareTo(i2);}
if (lResult == 0) {
String t1= (String)m1.get("surname2");
String t2= (String)m2.get("surname2");
if((t1 == null) || (t2==null)) {lResult = 0;}
else {lResult = t1.compareTo(t2);}
}
if (lResult == 0) {
String x1= (String)m1.get("name");
String x2= (String)m2.get("name ");
if((x1 == null) || (x2==null)) {lResult = 0;}
else {lResult = x1.compareTo(x2);}
}
return lResult;
}
});
无论速度如何,您的比较器都不正确。
唯一应该被认为是平等的东西,呃,平等的东西。您当前会认为 null
等于 "non-null"
,因此这会导致奇怪的行为。
具体来说,您似乎在比较第一对对应的值,它们都是 non-null。这违反了 Comparator 实现的传递性要求。考虑一下,例如:
A = {"surname1": "A", "surname2", null, "name": "A"}
B = {"surname1": null, "surname2", "B", "name": "B"}
C = {"surname1": "A", "surname2", "C", "name": null}
根据您的比较器,A < B
和 B < C
。然而,A == C
,因此使它成为一个无效的比较器。
正确地编写此比较器的最简单方法如下:
nullsLast(comparing(m -> (String) m.get("surname1")))
.thenComparing(nullsLast(comparing(m -> (String) m.get("surname2"))))
.thenComparing(nullsLast(comparing(m -> (String) m.get("name"))));
其中 nullsLast
和 comparing
是来自 Comparator
的方法。 (可以使用 nullsFirst
来代替,如果您更愿意这样处理空值的话)。
对于pre-Java8,你可以使用辅助方法写一个等价的比较:
public int compare(Map m1, Map m2) {
int lResult;
lResult = compare(m1, m2, "surname1");
if (lResult != 0) return lResult;
lResult = compare(m1, m2, "surname2");
if (lResult != 0) return lResult;
return compare(m1, m2, "name");
}
private int compare(Map m1, Map m2, String key) {
String v1= (String)m1.get(key);
String v2= (String)m2.get(key);
if (v1 != null && v2 != null) {
return v1.compareTo(v2);
}
return Boolean.compare(v1 != null, v2 != null);
}
或者使用类似 Guava 的 ComparisonChain
。