簡體   English   中英

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,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 <>)后,我將使用條件遍歷該列表。

 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

當涉及到排序時,通常只是關於如何實現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. Queue列編號
    2. 顧客姓名
  3. 如果一個擁有客戶編號,而另一個沒有客戶編號,則將具有空客戶編號的那個視為更大。

如果您確實需要尋找的東西,這並不難。 例如,對於單獨的案例,您可以有兩個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,這是有關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等工具,它看起來會更好)

您的方法是正確的,我如下測試。 注意優化是在排序而不是在比較功能時完成的。 由於您將使用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();
        }
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM