Java 多列条件排序
Java sorting with multiple column conditions
我有这个对象 ClientSearch
public class ClientSearch{
private Long clientNumber;
private String queueNumber;
private String clientName;
private String customerName;
.....
}
我需要按照这个规则排序:
先clientNumber降序显示,再按customerName降序显示,显示所有带clientNumber的记录后,按queueNumber降序排序,customerName降序排序。
这应该是结果 --- ClientNumber desc then, CustomerName desc, then, QueueNumber desc then, CustomerName desc
ClientNumber ClientName CustomerName
987654 Client1 Xyz1
987654 Client2 Abc2
555555 Client3 zzzzz1
21212 XYZ1 aaaab
111111 Client10 cZ
111111 Client11 cY
Z1Z1Z1 ClientX zzzzz
Z1Z1Z1 ClientY yyyyy
X2X2X2 Clienxyz aaaaaa
HHHHHH ClientH bbbbbb
AAAAAA ClientA xxxxxx
基本上每个 ClientSearch 对象都有一个 clientNumber 或一个 queueNumber(如果没有客户编号,则 queuNumber 被认为是一个客户编号,这就是它显示在该列下的原因),
我想做的是,在我从查询中收到一个列表后(我无法控制,我只是收到了列表<>),我将使用条件遍历列表。
if clientNumber is present then add to a List<ClientSearch> withClientNumbers
else if queueNumber is present then add to a List<ClientSearch> withQueueNumbers
完成此操作后,我将使用比较 ClientSearch 的 clientNumber 的比较器对 withClientNumbers 进行排序,然后如果它们等于零,我将再与 ClientSearch 的 customerName 进行比较。我只需要将它们与 -1 相乘以确保它是 DESC。
我将对 queueNumbers 执行相同的操作,但使用不同的比较器。
然后我将创建一个新列表 newList 然后执行此操作
newList.addAll(withClientNumbers); //make sure this is first in the list
newList.addAll(queueNumbers); // so to satisfy the condition that queueNumbers are shown after a sorted clientNumbers.
你能推荐任何其他优雅的方法来做到这一点吗?我觉得我的方法不是最优化的。请注意,我使用的是 Java 1.6
你的方法是正确的,我刚刚测试如下。注意优化是在排序而不是比较函数中完成的。由于您将使用 Java 自己的排序方法,因此您不必担心优化问题。
基本上,您只是打破了 clientNumber 与 customerNames 的相等关系。在这里,我只是为了简单起见将队列编号作为客户编号。由于您已经制作了不同的列表,因此可以将相同的解决方案应用于两个列表,然后合并列表。下面的示例代码:
public class ClientSearch{
private String clientNumber;
// private String queueNumber;
private String clientName;
private String customerName;
public ClientSearch(String clientNumber, String clientName, String customerName) {
this.clientNumber = clientNumber;
//this.queueNumber = queueNumber;
this.clientName = clientName;
this.customerName = customerName;
}
public String toString(){
return clientNumber+" "+clientName+" "+customerName;
}
public static void main(String[] args) {
try {
BufferedReader br = new BufferedReader(new FileReader("input.txt"));
String tmp = null;
List<ClientSearch> list = new ArrayList<>();
while((tmp=br.readLine())!=null){
String split [] = tmp.split(" ");
list.add(new ClientSearch(split[0],split[1],split[2]));
}
System.out.println("Sorting.....");
list.sort(new Comparator<ClientSearch>() {
@Override
public int compare(ClientSearch o1, ClientSearch o2) {
int diff = o1.clientNumber.compareTo(o2.clientNumber);
return diff ==0 ? o1.customerName.compareTo(o2.customerName) : diff;
}
});
for (ClientSearch c : list){
System.out.println(c);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
当谈到排序时,通常只是关于如何实现 Comparator
。在这种情况下,您只需要一个 Comparator
将两个 ClientSearch
对象与您描述的方式进行比较。
如果您可以简化按
排序的要求,将会更加简洁
- 客户编号(最后为空)
- 队列 ID,然后
- 客户姓名
比较器就这么简单,Java 8:
import static java.util.Comparator.*;
....
Comparator<Customer> comparator =
comparing(Customer::getCustNumber, nullsLast(naturalOrder()))
.thenComparing(Customer::getQueueId)
.thenComparing(Customer::getCustName);
与您最初要求的有点不同。你问的是
- 如果两者都有客户编号,比较
- 客户编号
- 客户姓名
- 如果两者都没有Customer Number,比较
- 队列 ID
- 客户姓名
- 如果一个有 Customer Number 而另一个没有,则 Customer Number 为空的被视为更大。
如果你真的需要你正在寻找的东西,那并不难。例如,你可以有两个 Comparator
分别用于单独的案例,然后组合成一个 Comparator
,看起来像(借助 Java 8,应该不难写一个用于上一个 Java 版本,如果你明白的话):
public class ClientSearchComparator implements Comparator<ClientSearch> {
private static Comparator<ClientSearch> custNumberComparator =
Comparator.comparing(ClientSearch::getCustNumber)
.thenComparing(ClientSearch::getCustName);
private static Comparator<ClientSearch> queueIdComparator =
Comparator.comparing(ClientSearch::getQueueId)
.thenComparing(ClientSearch::getCustName);
@Override
public int compare(ClientSearch c1, ClientSearch c2) {
if (c1.getCustNumber() != null && c2.getCustNumber() != null) {
return custIdComparator.compare(c1, c2);
} else if (c1.getCustNumber() == null && c2.getCustNumber() == null) {
return queueIdComparator.compare(c1, c2);
} else if (c1.getCustNumber() != null && c2.getCustNumber() == null) {
return -1;
} else { // (c1.getCustNumber() == null && c2.getCustNumber() != null)
return 1;
}
}
}
(我相信我不需要告诉你如何使用 Comparator
进行排序吧?)
更新:
正如您提到的,您正在使用 Java 6,这里是比较器的基本概念(伪代码):
public class ClientSearchComparator implements Comparator<ClientSearch> {
@Override
public int compare(ClientSearch c1, ClientSearch c2) {
if (c1.custNum != null && c2.custNum != null) {
if (c1.custNum != c2.custNum) {
return c1.custNum.compareTo(c2.custNum);
}
return c1.custName.compareTo(c2.custName);
} else if (c1.custNum == null && c2.custNum == null) {
if (c1.queueId != c2.queueId) {
return c1.queueId .compareTo(c2.queueId);
}
return c1.custName.compareTo(c2.custName);
} else if (c1.custNum == null) { // c1 null && c2 not null
return 1;
} else { // c1 not null && c2 null
return -1;
}
}
(经过一些重组,或者借助像 Guava 或 Apache Common Langs 这样的工具,它看起来会更好)
我有这个对象 ClientSearch
public class ClientSearch{
private Long clientNumber;
private String queueNumber;
private String clientName;
private String customerName;
.....
}
我需要按照这个规则排序:
先clientNumber降序显示,再按customerName降序显示,显示所有带clientNumber的记录后,按queueNumber降序排序,customerName降序排序。
这应该是结果 --- ClientNumber desc then, CustomerName desc, then, QueueNumber desc then, CustomerName desc
ClientNumber ClientName CustomerName
987654 Client1 Xyz1
987654 Client2 Abc2
555555 Client3 zzzzz1
21212 XYZ1 aaaab
111111 Client10 cZ
111111 Client11 cY
Z1Z1Z1 ClientX zzzzz
Z1Z1Z1 ClientY yyyyy
X2X2X2 Clienxyz aaaaaa
HHHHHH ClientH bbbbbb
AAAAAA ClientA xxxxxx
基本上每个 ClientSearch 对象都有一个 clientNumber 或一个 queueNumber(如果没有客户编号,则 queuNumber 被认为是一个客户编号,这就是它显示在该列下的原因),
我想做的是,在我从查询中收到一个列表后(我无法控制,我只是收到了列表<>),我将使用条件遍历列表。
if clientNumber is present then add to a List<ClientSearch> withClientNumbers
else if queueNumber is present then add to a List<ClientSearch> withQueueNumbers
完成此操作后,我将使用比较 ClientSearch 的 clientNumber 的比较器对 withClientNumbers 进行排序,然后如果它们等于零,我将再与 ClientSearch 的 customerName 进行比较。我只需要将它们与 -1 相乘以确保它是 DESC。
我将对 queueNumbers 执行相同的操作,但使用不同的比较器。
然后我将创建一个新列表 newList 然后执行此操作
newList.addAll(withClientNumbers); //make sure this is first in the list
newList.addAll(queueNumbers); // so to satisfy the condition that queueNumbers are shown after a sorted clientNumbers.
你能推荐任何其他优雅的方法来做到这一点吗?我觉得我的方法不是最优化的。请注意,我使用的是 Java 1.6
你的方法是正确的,我刚刚测试如下。注意优化是在排序而不是比较函数中完成的。由于您将使用 Java 自己的排序方法,因此您不必担心优化问题。 基本上,您只是打破了 clientNumber 与 customerNames 的相等关系。在这里,我只是为了简单起见将队列编号作为客户编号。由于您已经制作了不同的列表,因此可以将相同的解决方案应用于两个列表,然后合并列表。下面的示例代码:
public class ClientSearch{
private String clientNumber;
// private String queueNumber;
private String clientName;
private String customerName;
public ClientSearch(String clientNumber, String clientName, String customerName) {
this.clientNumber = clientNumber;
//this.queueNumber = queueNumber;
this.clientName = clientName;
this.customerName = customerName;
}
public String toString(){
return clientNumber+" "+clientName+" "+customerName;
}
public static void main(String[] args) {
try {
BufferedReader br = new BufferedReader(new FileReader("input.txt"));
String tmp = null;
List<ClientSearch> list = new ArrayList<>();
while((tmp=br.readLine())!=null){
String split [] = tmp.split(" ");
list.add(new ClientSearch(split[0],split[1],split[2]));
}
System.out.println("Sorting.....");
list.sort(new Comparator<ClientSearch>() {
@Override
public int compare(ClientSearch o1, ClientSearch o2) {
int diff = o1.clientNumber.compareTo(o2.clientNumber);
return diff ==0 ? o1.customerName.compareTo(o2.customerName) : diff;
}
});
for (ClientSearch c : list){
System.out.println(c);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
当谈到排序时,通常只是关于如何实现 Comparator
。在这种情况下,您只需要一个 Comparator
将两个 ClientSearch
对象与您描述的方式进行比较。
如果您可以简化按
排序的要求,将会更加简洁- 客户编号(最后为空)
- 队列 ID,然后
- 客户姓名
比较器就这么简单,Java 8:
import static java.util.Comparator.*;
....
Comparator<Customer> comparator =
comparing(Customer::getCustNumber, nullsLast(naturalOrder()))
.thenComparing(Customer::getQueueId)
.thenComparing(Customer::getCustName);
与您最初要求的有点不同。你问的是
- 如果两者都有客户编号,比较
- 客户编号
- 客户姓名
- 如果两者都没有Customer Number,比较
- 队列 ID
- 客户姓名
- 如果一个有 Customer Number 而另一个没有,则 Customer Number 为空的被视为更大。
如果你真的需要你正在寻找的东西,那并不难。例如,你可以有两个 Comparator
分别用于单独的案例,然后组合成一个 Comparator
,看起来像(借助 Java 8,应该不难写一个用于上一个 Java 版本,如果你明白的话):
public class ClientSearchComparator implements Comparator<ClientSearch> {
private static Comparator<ClientSearch> custNumberComparator =
Comparator.comparing(ClientSearch::getCustNumber)
.thenComparing(ClientSearch::getCustName);
private static Comparator<ClientSearch> queueIdComparator =
Comparator.comparing(ClientSearch::getQueueId)
.thenComparing(ClientSearch::getCustName);
@Override
public int compare(ClientSearch c1, ClientSearch c2) {
if (c1.getCustNumber() != null && c2.getCustNumber() != null) {
return custIdComparator.compare(c1, c2);
} else if (c1.getCustNumber() == null && c2.getCustNumber() == null) {
return queueIdComparator.compare(c1, c2);
} else if (c1.getCustNumber() != null && c2.getCustNumber() == null) {
return -1;
} else { // (c1.getCustNumber() == null && c2.getCustNumber() != null)
return 1;
}
}
}
(我相信我不需要告诉你如何使用 Comparator
进行排序吧?)
更新: 正如您提到的,您正在使用 Java 6,这里是比较器的基本概念(伪代码):
public class ClientSearchComparator implements Comparator<ClientSearch> {
@Override
public int compare(ClientSearch c1, ClientSearch c2) {
if (c1.custNum != null && c2.custNum != null) {
if (c1.custNum != c2.custNum) {
return c1.custNum.compareTo(c2.custNum);
}
return c1.custName.compareTo(c2.custName);
} else if (c1.custNum == null && c2.custNum == null) {
if (c1.queueId != c2.queueId) {
return c1.queueId .compareTo(c2.queueId);
}
return c1.custName.compareTo(c2.custName);
} else if (c1.custNum == null) { // c1 null && c2 not null
return 1;
} else { // c1 not null && c2 null
return -1;
}
}
(经过一些重组,或者借助像 Guava 或 Apache Common Langs 这样的工具,它看起来会更好)