具有多个列条件的Java排序

时间:2016-11-02 06:23:54

标签: java sorting comparator

我有这个对象ClientSearch

public class ClientSearch{
private Long clientNumber;
private String queueNumber;
private String clientName;
private String customerName;
.....
}

我需要按照这条规则对此进行排序:

显示clientNumber先降序,然后按customerName降序显示,显示所有带有clientNumber的记录后,按降序排列queueNumber,按降序排序。

这应该是结果--- ClientNumber desc然后,CustomerName desc,然后,QueueNumber desc,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视为一个客户端编号,说明它在该列下显示的原因),

我想做的是,在我从查询中收到一个List(我无法控制,我刚刚收到List<>)之后,我将使用条件遍历列表。

 if clientNumber is present then add to a List<ClientSearch> withClientNumbers

 else if queueNumber is present then add to a List<ClientSearch> withQueueNumbers

执行此操作后,我会使用比较ClientClumber的clientNumber的比较器对withClientNumbers进行排序,然后如果它们等于0,则与ClientSearch的customerName进行比较。我只需要将它们与-1相乘以确保它是DESC。

我将对queueNumbers执行相同操作,但使用不同的比较器。

然后我创建一个新的List 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

2 个答案:

答案 0 :(得分:2)

在排序方面,通常只是关于如何实施Comparator。在这种情况下,您只需要一个Comparator,可以按照您描述的方式比较两个ClientSearch个对象。

如果您可以简化排序要求

,那将会更加清晰
  1. 客户编号(最后为空)
  2. 队列ID,然后
  3. 客户名称
  4. 比较器将如此简单,使用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. 如果有一个客户编号,而另一个没有客户编号,那么具有空客户编号的客户编号将被视为更大。
    4. 如果你真的需要你想要的东西,那就不难做到。例如,对于单独的case,你可以有两个Comparator,然后将它们合并为一个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这样的工具,它看起来会更好)

答案 1 :(得分:0)

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

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