如何通过几个字段改进对象的比较器?如果姓氏不存在,比较器必须按姓氏或名字对用户进行排序。如果没有姓和名,则按用户名排序。但是这些用户必须位于列表的末尾。
public static Comparator<UserConfigurationDto> BY_LASTNAME = (u1, u2) -> {
// if users have only username compare them
if((u1.getLastName().isEmpty() && u1.getFirstName().isEmpty())
&& (u2.getLastName().isEmpty() && u2.getFirstName().isEmpty())){
return u1.getUsername().compareToIgnoreCase(u2.getUsername());
}
//if user doesnt have firstName and LastName drop them at the end
if(u1.getLastName().isEmpty() && u1.getFirstName().isEmpty()){
return 1000000 + getWeight(u1.getUsername());
}
if(u2.getLastName().isEmpty() && u2.getFirstName().isEmpty()){
return -1000000 + getWeight(u2.getUsername());
}
String s1 = u1.getLastName().isEmpty() ? u1.getFirstName() : u1.getLastName();
String s2 = u2.getLastName().isEmpty() ? u2.getFirstName() : u2.getLastName();
return s1.compareToIgnoreCase(s2);
};
}
private static int getWeight(String s){
return s.codePoints().sum();
}
有人知道如何改善这一点吗?我尝试使用Comparator.comparing和Comparator.thenComparing,但它们会产生错误的结果
答案 0 :(得分:1)
1)不需要return 1000000 + getWeight(u1.getUsername());
和return -1000000 + getWeight(u2.getUsername());
。如果您参考return 1
javadoc,则return -1
和CompareTo()
会更清晰,并产生相同的结果:
将此对象与指定对象进行比较。返回一个 负整数,零或正整数,因为此对象较少 大于,等于或大于指定的对象
2)您没有链接字段比较,但是根据比较对象的状态有3种排序方式。因此,定义每个案例的代码有点冗长这一事实最终是正常的。
复制很多user.getLastName().isEmpty()
调用时,您都可以使用提取方法来减少它。
例如:
public static Comparator<UserConfigurationDto> BY_LASTNAME = (u1, u2) -> {
// first case
if( u1.isLastAndFirstNameEmpty() && u2.isLastAndFirstNameEmpty()){
return u1.getUsername().compareToIgnoreCase(u2.getUsername());
}
// second case
if(u1.isLastAndFirstNameEmpty()){
return 1;
}
else if(u2.isLastAndFirstNameEmpty()){
return -1;
}
// third case
String s1 = u1.getLastName().isEmpty() ? u1.getFirstName() : u1.getLastName();
String s2 = u2.getLastName().isEmpty() ? u2.getFirstName() : u2.getLastName();
return s1.compareToIgnoreCase(s2);
};
答案 1 :(得分:1)
您要去哪里的地方是尝试应用“重量”的概念。用Java处理比较器时,从函数中出来的唯一重要的值是0,大于0和小于0。
类似的事情似乎起作用:
public static final Comparator<UserConfgurationDto> BY_LASTNAME = ( u1, u2 ) ->
{
boolean u1hasName = !u1.getLastName().isEmpty() || !u1.getFirstName().isEmpty();
boolean u2hasName = !u2.getLastName().isEmpty() || !u2.getFirstName().isEmpty();
if ( u1hasName && !u2hasName )
{
// u1 < u2
return -1;
}
else if ( !u1hasName && u2hasName )
{
// u2 < u1
return 1;
}
else if ( u1hasName && u2hasName )
{
String s1 = u1.getLastName().isEmpty() ? u1.getFirstName() : u1.getLastName();
String s2 = u2.getLastName().isEmpty() ? u2.getFirstName() : u2.getLastName();
return s1.compareToIgnoreCase( s2 );
}
else
{
return u1.getUsername().compareToIgnoreCase( u2.getUsername() );
}
};
答案 2 :(得分:1)
我认为您可以使用Java 8静态comparing function that includes the key comparator来实现此目的。 String有一个方便的case insensitive comparator,您也可以在几个地方使用它。
Comparator.comparing(
(UserConfigurationDto u) -> u.getLastName().isEmpty()?u.getFirstName():u.getLastName(),
((s1, s2) -> {
if(s1.isEmpty()) {
return 1;
} else if(s2.isEmpty()) {
return -1;
}
else {
return String.CASE_INSENSITIVE_ORDER.compare(s1, s2);
}
}))
.thenComparing(UserConfigurationDto::getUsername, String.CASE_INSENSITIVE_ORDER);
答案 3 :(得分:0)
以heisbrandon的答案为基础,但进一步考虑到两个空字符串相等(因此将触发对thenComparing
的调用),您实际上可以简化代码。假设比较两个姓氏缺失的用户与比较两个姓氏相同的用户,等等。
public static Comparator<UserConfigurationDto> BY_LASTNAME =
Comparator.comparing(UserConfigurationDto::getLastName)
.thenComparing(UserConfigurationDto::getFirstName)
.thenComparing(UserConfigurationDto::getUsername);