英文:
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;
}
});
英文:
Is there any way to order people name's by surname1, if not, surname2, if not, name, more efficiently than this?
This is too slow, thanks!
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;
}
});
答案1
得分: 3
不管速度如何,你的比较器都是不正确的。
唯一应该被视为相等的是相等的事物。你目前会认为 null
等于 "non-null"
,所以这会导致奇怪的行为。
具体来说,你似乎正在比较第一对同时非空的对应值。这违反了比较器实现的传递性要求。例如,考虑以下情况:
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
中的方法。(如果你更喜欢处理 nulls 的话,可以使用 nullsFirst
代替)。
在 Java 8 之前,你可以使用一个辅助方法编写等效的比较:
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
。
英文:
Irrespective of speed, your comparator isn't correct.
The only things which should be considered equal are, well, equal things. You would currently consider null
to be equal to "non-null"
, and so that would lead to odd behavior.
Specifically, what you seem to be doing is comparing the first pair of corresponding values which are both non-null. This violates the transitivity requirement of Comparator implementations. Consider, for example:
A = {"surname1": "A", "surname2", null, "name": "A"}
B = {"surname1": null, "surname2", "B", "name": "B"}
C = {"surname1": "A", "surname2", "C", "name": null}
According to your comparator, A < B
and B < C
. However, A == C
, thus making it an invalid comparator.
The easiest way to write this Comparator - correctly - would be something like:
nullsLast(comparing(m -> (String) m.get("surname1")))
.thenComparing(nullsLast(comparing(m -> (String) m.get("surname2"))))
.thenComparing(nullsLast(comparing(m -> (String) m.get("name"))));
where nullsLast
and comparing
are methods from Comparator
. (nullsFirst
can be used instead, if that's how you'd prefer to handle nulls).
With pre-Java 8, you can write an equivalent comparison using a helper method:
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);
}
Or use something like Guava's ComparisonChain
.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论