1. 程式人生 > 實用技巧 >java8如何對list中的map元素根據多個key值進行排序

java8如何對list中的map元素根據多個key值進行排序

使用JAVA自己的排序方法,有的時候是一個可行的選擇。

先從簡單的開始說起。

一、少數key的情況

有一個需求:根據 menu_level,sort排序,越小的越前面。

--

下面程式碼按照升序規則進行!

--

Collections.sort(menuList, new Comparator<Map<String, Object>>() {
@Override
public int compare(Map<String, Object> o1, Map<String, Object> o2) {
// 進行判斷

//compareTo當前面小於後面的時候,返回-1。也就是說如果要倒序,那麼只要返回1即可。
int cpLevel=((Integer) o1.get("menu_level")).compareTo((Integer) o2.get("menu_level"));
Integer sort1=(o1.get("sort")==null)?10000:(Integer) o1.get("sort");
Integer sort2=(o2.get("sort")==null)?10000:(Integer) o2.get("sort");
int cpSort=sort1.compareTo(sort2);
if (cpLevel==1) {
return 1;
}
else if(cpLevel==0) {
return cpSort;
}
else {
return -1;
}
//return ;
}
});

---

現在稍微複雜下,後文是3個key的比較。

譬如有資料表books,它們的資料如下:select * from books order by author,price desc,publisher

2 102 生命在於運動 lml 1000.00 中華出版社
5 103 2020年異象 lml 90.00 福建出版社
9 108 以史鑑今 lml 90.00 西安出版社
4 104 奮鬥在上海 lzf 1000.00 publzf
8 107 學習方法論 lzf 99.00 中天出版社
7 106 論自力更生的必要性 lzf 99.00 秦皇漢武
3 1498591124 Professional Java for Web Applications Nicholas S. Williams 59.99 John Wiley & Sons
6 105 21世紀-中國-前進 五十 83.00 附件出版社

現在希望通過java排序, 程式碼如下:

@Override
    public List<Map<String, Object>> sortByNKeys() {
        String sql = "select author,price,publisher,isbn,title from books";
        List<Map<String, Object>> bookList = jdbcTp.queryForList(sql);

        // 使用java 8的 stream 功能進行排序
        // order by author,price desc,publisher
        /**
         * 升序返回-1,倒序返回1即可 有多個key需要比較的時候(不考慮null或者""的情況),當第n個key返回的是0的時候繼續比較,如果不是
         * 則根據第n個key的比較值返回需要的結果。 譬如第1個key的比較結果是0,則比驕傲第2個, 假定第二的key的比較結果是-1
         * 如果要根據第二個倒序,則返回1;如果要根據第二個升序,則直接發那會-1即可 以此類推
         */

        Collections.sort(bookList, new Comparator<Map<String, Object>>() {
            @Override
            public int compare(Map<String, Object> o1, Map<String, Object> o2) {
                // 進行判斷
                int cp1 = ((String) o1.get("author")).compareTo((String) o2
                        .get("author"));
                BigDecimal price1 = new BigDecimal(o1.get("price").toString());
                BigDecimal price2 = new BigDecimal(o1.get("price").toString());
                int cp2 = price1.compareTo(price2);

                String p1 = o1.get("publisher").toString();
                String p2 = o2.get("publisher").toString();
                int cp3 = p1.compareTo(p2);

                if (cp1 == 0) {
                    if (cp2 == 0) {
                        if (cp3 == 0) {
                            return 0;
                        } else {
                            return cp3;
                        }
                    } else {
                        return cp2 * -1;
                    }
                } else {
                    return cp1;
                }
                // return ;
            }
        });

        return bookList;
    }

結果輸出如下:

[{
    "author": "Nicholas S. Williams",
    "price": 59.99,
    "publisher": "John Wiley & Sons",
    "isbn": "1498591124",
    "title": "Professional Java for Web Applications"
}, {
    "author": "lml",
    "price": 1000.00,
    "publisher": "中華出版社",
    "isbn": "102",
    "title": "生命在於運動"
}, {
    "author": "lml",
    "price": 90.00,
    "publisher": "福建出版社",
    "isbn": "103",
    "title": "2020年異象"
}, {
    "author": "lml",
    "price": 90.00,
    "publisher": "西安出版社",
    "isbn": "108",
    "title": "以史鑑今"
}, {
    "author": "lzf",
    "price": 1000.00,
    "publisher": "publzf",
    "isbn": "104",
    "title": "奮鬥在上海"
}, {
    "author": "lzf",
    "price": 99.00,
    "publisher": "中天出版社",
    "isbn": "107",
    "title": "學習方法論"
}, {
    "author": "lzf",
    "price": 99.00,
    "publisher": "秦皇漢武",
    "isbn": "106",
    "title": "論自力更生的必要性"
}, {
    "author": "五十",
    "price": 83.00,
    "publisher": "附件出版社",
    "isbn": "105",
    "title": "21世紀-中國-前進"
}]

注:之所以,有所區別,是因為mysql比較的時候,預設不考慮大小寫;而java字串的CompareTo則是按照unicode編碼比較進行的。

二、不定個數key的情況

以上可以應付一些簡單的要求,如果有不斷變化的,任意個數的key需要比較,那麼怎麼做?

可以參考的一個終極方案,程式碼如下:

public void sort() {
        String dataJson="[{\r\n" + 
                "    \"author\": \"Nicholas S. Williams\",\r\n" + 
                "    \"price\": 59.99,\r\n" + 
                "    \"publisher\": \"John Wiley & Sons\",\r\n" + 
                "    \"isbn\": \"1498591124\",\r\n" + 
                "    \"title\": \"Professional Java for Web Applications\"\r\n" + 
                "}, {\r\n" + 
                "    \"author\": \"lml\",\r\n" + 
                "    \"price\": 1000.00,\r\n" + 
                "    \"publisher\": \"中華出版社\",\r\n" + 
                "    \"isbn\": \"102\",\r\n" + 
                "    \"title\": \"生命在於運動\"\r\n" + 
                "}, {\r\n" + 
                "    \"author\": \"lml\",\r\n" + 
                "    \"price\": 90.00,\r\n" + 
                "    \"publisher\": \"福建出版社\",\r\n" + 
                "    \"isbn\": \"103\",\r\n" + 
                "    \"title\": \"2020年異象\"\r\n" + 
                "}, {\r\n" + 
                "    \"author\": \"lml\",\r\n" + 
                "    \"price\": 90.00,\r\n" + 
                "    \"publisher\": \"西安出版社\",\r\n" + 
                "    \"isbn\": \"108\",\r\n" + 
                "    \"title\": \"以史鑑今\"\r\n" + 
                "}, {\r\n" + 
                "    \"author\": \"lzf\",\r\n" + 
                "    \"price\": 1000.00,\r\n" + 
                "    \"publisher\": \"publzf\",\r\n" + 
                "    \"isbn\": \"104\",\r\n" + 
                "    \"title\": \"奮鬥在上海\"\r\n" + 
                "}, {\r\n" + 
                "    \"author\": \"lzf\",\r\n" + 
                "    \"price\": 99.00,\r\n" + 
                "    \"publisher\": \"中天出版社\",\r\n" + 
                "    \"isbn\": \"107\",\r\n" + 
                "    \"title\": \"學習方法論\"\r\n" + 
                "}, {\r\n" + 
                "    \"author\": \"lzf\",\r\n" + 
                "    \"price\": 99.00,\r\n" + 
                "    \"publisher\": \"秦皇漢武\",\r\n" + 
                "    \"isbn\": \"106\",\r\n" + 
                "    \"title\": \"論自力更生的必要性\"\r\n" + 
                "}, {\r\n" + 
                "    \"author\": \"五十\",\r\n" + 
                "    \"price\": 83.00,\r\n" + 
                "    \"publisher\": \"附件出版社\",\r\n" + 
                "    \"isbn\": \"105\",\r\n" + 
                "    \"title\": \"21世紀-中國-前進\"\r\n" + 
                "}]";
        List<Map<String, Object>> dataList = JSON.parseObject(dataJson,new TypeReference<List<Map<String,Object>>>(){});
        System.out.println(dataList);
        
        List<Map<String,Object>> sortList=new ArrayList<Map<String,Object>>();
        Map<String,Object> a1=new HashMap<String,Object>();
        a1.put("code", "publisher");
        a1.put("sortPosition", 3);
        a1.put("sortDirection", "desc");
        sortList.add(a1);
        Map<String,Object> a2=new HashMap<String,Object>();
        a2.put("code", "author");
        a2.put("sortPosition", 2);
        a2.put("sortDirection", "asc");
        sortList.add(a2);
        Map<String,Object> a3=new HashMap<String,Object>();
        a3.put("code", "price");
        a3.put("sortPosition", 1);
        a3.put("sortDirection", "desc");
        sortList.add(a3);
        Map<String,Object> a4=new HashMap<String,Object>();
        a4.put("code", "title");
        a4.put("sortPosition", 4);
        a4.put("sortDirection", "asc");
        sortList.add(a4);
        Map<String,Object> a5=new HashMap<String,Object>();
        a5.put("code", "isbn");
        a5.put("sortPosition", 5);
        a5.put("sortDirection", "asc");
        sortList.add(a5);
        
        Collections.sort(sortList, new Comparator<Map<String, Object>>() {
            @Override
            public int compare(Map<String, Object> o1, Map<String, Object> o2) {
                // 進行判斷
                int cp1 = o1.get("sortPosition").toString().compareTo(o2.get("sortPosition").toString());
                return cp1;
            }
        });
        
        int sortSize=sortList.size();
        int[] compareResultArr=new int[sortSize];
        int[] sortDirectionArr=new int[sortSize];
        String[] colArr=new String[sortSize];
        for(int i=0;i<sortSize;i++) {
            compareResultArr[i]=0;
            sortDirectionArr[i]=sortList.get(i).get("sortDirection").equals("asc")?1:-1;
            colArr[i]=sortList.get(i).get("code").toString();
        }
        
        
        //排序的時候,必須保證多行在custom_id之後,而單行在custom_id之前,避免資料混亂
        Collections.sort(dataList, new Comparator<Map<String, Object>>() {
            @Override
            public int compare(Map<String, Object> o1, Map<String, Object> o2) {
                // 進行判斷
                for(int i=0,len=sortSize;i<len;i++) {
                    Object v1=o1.get(colArr[i]);
                    Object v2=o2.get(colArr[i]);
                    if (v1 instanceof String) {
                        compareResultArr[i]=v1.toString().compareTo(v2.toString());
                    }
                    else {
                        compareResultArr[i]=new BigDecimal(v1.toString()).compareTo(new BigDecimal(v2.toString()));
                    }
                    
                }
                   
                for(int i=0,len=sortSize;i<len;i++) {
                    if (compareResultArr[i]!=0) {
                        return compareResultArr[i]*sortDirectionArr[i];
                    }
                }
                //如果都是一樣,則直接返回0
                return 0;
            }
        });
        
        System.out.println(dataList);
    }

解決思路也比較簡單:

1)使用陣列儲存每個key的比較值和排序方向值(升序1,降序-1)

2)對比較的結果迴圈判斷,只要有不等於0(相等的)就返回

上面的解決還比較粗暴,可以稍微改進下:

Collections.sort(dataList, new Comparator<Map<String, Object>>() {
            @Override
            public int compare(Map<String, Object> o1, Map<String, Object> o2) {
                // 進行判斷
                for(int i=0,len=sortSize;i<len;i++) {
                    Object v1=o1.get(colArr[i]);
                    Object v2=o2.get(colArr[i]);
                    if (v1 instanceof String) {
                        compareResultArr[i]=v1.toString().compareTo(v2.toString());
                    }
                    else {
                        compareResultArr[i]=new BigDecimal(v1.toString()).compareTo(new BigDecimal(v2.toString()));
                    }
//只要有一個不相等,就可以返回了
if (compareResultArr[i]*sortDirectionArr[i]!=0){
return compareResultArr[i]*sortDirectionArr[i];
} }//如果都是一樣,則直接返回0 return 0; } });

注意:

1)以上方案沒有考慮更多的型別,都是java的基本包裝類

2) 不適合要求高效能的環境。如有需要,應該考慮購買演算法,或者是使用其它演算法計算

3)如果您的應用排序的資料大概是一萬行內,且對時間要求不是特別高,那麼可以使用以上方法。