我有一个自定义类型的数组,我想按其String属性之一进行排序。出于某种原因,以下代码产生错误的结果。你能指出我可能犯错的地方吗?
class PatientLNComparator implements Comparator<Patient>{
@Override
public int compare(Patient p1, Patient p2) {
String p1_LN = (p1 == null) ? null : p1.last_name;
String p2_LN = (p2 == null) ? null : p2.last_name;
if(p2_LN == null)
return -1;
else if(p1_LN == null)
return +1;
else if(p1_LN.equals(p2_LN))
return 0;
else if(p1_LN.compareTo(p2_LN) > 0)
return -1;
else
return +1;
}
}
答案 0 :(得分:2)
一个问题一开始 - 如果您给两名患有空名称的患者或两名空患者参考,您的比较器就会不一致。特别是:
Patient p1 = null;
Patient p2 = null;
int x = comparator.compare(p1, p2);
int y = comparator.compare(p2, p1);
x
和y
的迹象应该不同 - 但它们都是-1。
之后,这取决于您想要如何比较名称。我通常会使用
return p1_LN.compareTo(p2_LN);
如果您想按升序排序。请注意,要按降序顺序排序,您不应该只返回-p1_LN.compareTo(p2_LN)
,就像比较返回Integer.MIN_VALUE一样,否定将无效。相反,您需要返回p2_LN.compareTo(p1_LN);
。
请注意,如果您使用此方案,则无需拨打p1_LN.equals(p2_LN)
- 这将由compareTo
电话处理。
答案 1 :(得分:1)
我假设你想要自然的字符串排序。
首先,就像它一样,你的compareTo分支给出了反转的结果。不知道这是不是你的意图(正如你所说的,当p1的字符串低于p2时,p1大于p2)。
此外,您可以放弃if的.equals分支。 compareTo已经处理了这种情况。
因此简单
if(p2_LN == null && p1_LN == null)
return 0;
else if(p1_LN == null)
return +1;
else if(p2_LN == null)
return -1;
else return p1_LN.compareTo(p2_LN)
就足够了。
答案 2 :(得分:1)
您希望患者按姓氏按字母顺序排序,无效患者和前排空姓?
class PatientLNComparator implements Comparator<Patient>{
@Override
public int compare(Patient p1, Patient p2) {
String p1_LN = (p1 == null) ? null : p1.last_name;
String p2_LN = (p2 == null) ? null : p2.last_name;
if (p1_LN == null && p2_LN == null)
return 0;
else if (p2_LN == null)
return -1;
else if(p1_LN == null)
return +1;
else
return p1_LN.compareTo(p2_LN);
}
}
为了保持稳定,当姓氏相同时,它应该通过其他一些字段排序,例如名字。
答案 3 :(得分:0)
class Patient {
// ...
public static final Function<Patient, String> GET_LAST_NAME =
new Function<Patient, String>() {
public String apply(Patient from) {
if (from == null) return null;
return from.last_name;
}
};
public static final Comparator<Patient> BY_LAST_NAME =
Ordering.natural()
.onResultOf(GET_LAST_NAME)
.nullsFirst();
}
这将解决空值比较不一致的问题。它还可以轻松添加二级订单(例如名字):
public static final Comparator<Patient> BY_LAST_NAME =
Ordering.natural()
.onResultOf(GET_LAST_NAME)
.compound(Ordering.natural().onResultOf(GET_FIRST_NAME))
.nullsFirst();