【问题标题】:Java sorting with multiple column conditions具有多列条件的 Java 排序
【发布时间】:2016-11-02 06:23:53
【问题描述】:

我有这个对象 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

完成此操作后,我将使用比较器对 withClientNumbers 进行排序,该比较器比较 ClientSearch 的 clientNumber,然后如果它们等于零,我将再次与 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

【问题讨论】:

  • 在您的表格中您显示了“clientName”,但在您的文字描述中,您在两种情况下都使用了“customerName”。你能澄清一下吗?而且,让 Comparator 比较 ClientNumber (null last) 然后 Queue Number 然后 Customer Name 有什么问题?
  • 对于任何阅读本文并且可以使用 Java 8 的人的注意事项:有一种非常优雅的链接比较条件的方法:humans.sort(Comparator.comparing(Human::getName).thenComparing(Human::getAge)); 请参阅baeldung.com/java-8-sort-lambda 以获取完整说明

标签: java sorting comparator


【解决方案1】:

当涉及到排序时,通常只是关于如何实现Comparator。在这种情况下,您只需要一个 Comparator 将两个 ClientSearch 对象与您描述的方式进行比较。

如果你能简化你的排序要求,那会更简洁

  1. 客户编号(最后为空)
  2. 队列 ID,然后
  3. 客户名称

使用 Java 8,比较器就这么简单:

import static java.util.Comparator.*;
....
Comparator<Customer> comparator = 
    comparing(Customer::getCustNumber, nullsLast(naturalOrder()))
    .thenComparing(Customer::getQueueId)
    .thenComparing(Customer::getCustName);

这与您最初要求的有点不同。你要求的是

  1. 如果两者都有客户编号,则比较
    1. 客户编号
    2. 客户名称
  2. 如果两者都没有客户编号,则比较
    1. 队列 ID
    2. 客户名称
  3. 如果一个有客户编号而另一个没有,则客户编号为空的那个被视为更大。

如果你真的需要你正在寻找的东西,这并不难。例如,您可以将两个Comparators 分别用于单独的情况,然后将其组合为一个Comparator,看起来像(借助Java 8,如果您得到,应该不难为prev 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,以下是 Comparator 外观的基本概念(伪代码):

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 等工具,它看起来会更好)

【讨论】:

    【解决方案2】:

    你的方法是正确的,我只是测试如下。注意优化是在排序中完成的,而不是在比较函数中。由于您将使用 Java 自己的排序方法,因此您不必担心优化。 基本上,您只是打破了 clientNumber 与 customerNames 的平等关系。在这里,为了简单起见,我将 queuenumbers 作为 clientnumbers。由于您已经制作了不同的列表,因此可以将相同的解决方案应用于两个列表,然后合并列表。下面的示例代码:

    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();
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-03-30
      • 1970-01-01
      • 2013-11-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多