Java中Map 存儲結構根據值排序(sort by values)


需求:Map<key, value>中可以根據key, value 進行排序,由於 key 都是唯一的,可以很方便的進行比較操作,但是每個key 對應的value不是唯一的,有可能出現多個 相同的value對應key 是不一樣的,所以需要采用不一樣的方式。

詳解:Map<key, value> 的目的是用來快速訪問的存儲結構。

通用的方法:

package com.compare;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.*;

public class MapUtil {
  
    public static <K, V extends Comparable<? super V>> Map<K, V> sortByValue(Map<K, V> map) {
    	
//    	1、通過調用Map的entrySet()方法獲取所有條目
        List<Entry<K, V>> list = new ArrayList<>(map.entrySet());
//      2、創建自定義比較器以根據值對條目進行排序
//      3、將條目集轉換為列表
//      4、sort()方法通過傳遞值比較器對條目列表進行排序, 也可以通過調用Collections.Sort(),之后的案例中會有介紹
        list.sort(Entry.comparingByValue());

        Map<K, V> result = new LinkedHashMap<>();
//      5、通過按排序順序添加條目來創建LinkedHashMap。
        for (Entry<K, V> entry : list) {
            result.put(entry.getKey(), entry.getValue());
        }

        return result;
    }
    
}

 

package com.compare;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;

public class test {

	public static void main(String[] args) {
	
		Map<Integer, Integer> node_finalWeight = new HashMap();
		
		node_finalWeight.put(5, 5);
		node_finalWeight.put(35, 6);
		node_finalWeight.put(45, 4);
		node_finalWeight.put(25, 3);
		node_finalWeight.put(20, 3);
		
		System.out.println("按值排序之前:" +node_finalWeight);
		MapUtil mu = new MapUtil();  
		// 類實例化后直接調用方法
		System.out.println("按值排序之后:" + mu.sortByValue(node_finalWeight)  );
		

	}
}

輸出結果:

按值排序之前:{35=6, 20=3, 5=5, 25=3, 45=4}
按值排序之后:{20=3, 25=3, 45=4, 5=5, 35=6}

值得注意的是:

Map是java中的接口,Map.Entry是Map的一個內部接口。

Map提供了一些常用方法,如keySet()、entrySet()等方法。

keySet()方法返回值是Map中key值的集合;entrySet()的返回值也是返回一個Set集合,此集合的類型為Map.Entry。

Map.Entry是Map聲明的一個內部接口,此接口為泛型,定義為Entry<K,V>。它表示Map中的一個實體(一個key-value對)。

Map.entrySet 方法返回映射的 collection 視圖,其中的元素屬於此類。獲得映射項引用的唯一 方法是通過此 collection 視圖的迭代器來實現。這些 Map.Entry 對象僅 在迭代期間有效;更確切地講,如果在迭代器返回項之后修改了底層映射,則某些映射項的行為是不確定的,除了通過 setValue 在映射項上執行操作之外。

 

關於重寫Java里面的比較器,這里有幾篇文章寫的不錯:

https://www.baeldung.com/java-comparator-comparable

https://docs.oracle.com/javase/7/docs/api/java/util/Comparator.html

https://www.geeksforgeeks.org/comparator-interface-java/

https://www.cnblogs.com/shizhijie/p/7657049.html

 

 這里引用一下另外一個案例,作為參考: 

package com.sortbyvalue;


import java.text.ParseException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeMap;


public class SortingByHashMap{

    public static void main(String args[]) throws ParseException {
        
        // let's create a map with Java releases and their code names
        HashMap<String, Integer> originalData = new HashMap<String, Integer>();
        
        originalData.put("cangjie", 5);
        originalData.put("minghuang", 7);
        originalData.put("laozi", 5);
        originalData.put("tangtaizong", 8);
        originalData.put("simaqian", 9);     
        
        System.out.println("HashMap before sorting: ");
        Set<Entry<String, Integer>> entries = originalData.entrySet();
       
        for(Entry<String, Integer> entry : entries){
            System.out.println(entry.getKey() + " ==> " + entry.getValue());
        }
        

       
        Comparator<Entry<String, Integer>> valueComparator = new Comparator<Entry<String, Integer>>() {
            @Override
            public int compare(Entry<String, Integer> e1, Entry<String, Integer> e2) {
                Integer v1 = e1.getValue();
                Integer v2 = e2.getValue();
                return v1.compareTo(v2);
            }
        };
        
        // Sort method needs a List, so let's first convert Set to List in Java
        List<Entry<String, Integer>> listOfEntries = new ArrayList<Entry<String, Integer>>(entries);
        
        // sorting HashMap by values using comparator
        Collections.sort(listOfEntries, valueComparator);
        
        LinkedHashMap<String, Integer> sortedByValue = new LinkedHashMap<String, Integer>(listOfEntries.size());
        
        // copying entries from List to Map
        for(Entry<String, Integer> entry : listOfEntries){
            sortedByValue.put(entry.getKey(), entry.getValue());
        }
        
        System.out.println("HashMap after sorting entries by values ");
        Set<Entry<String, Integer>> entrySetSortedByValue = sortedByValue.entrySet();
        
        for(Entry<String, Integer> mapping : entrySetSortedByValue){
            System.out.println(mapping.getKey() + " ==> " + mapping.getValue());
        }
        
        
    }

}

 

附錄一下如果想直接通過key 排序的話,可以借用一下TreeMap 的結構:

package com.sortbyvalue;

import java.text.ParseException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeMap;


public class SortingByHashMap{

    public static void main(String args[]) throws ParseException {
        
        // let's create a map with Java releases and their code names
        HashMap<String, Integer> originalData = new HashMap<String, Integer>();
        
        originalData.put("cangjie", 5);
        originalData.put("minghuang", 7);
        originalData.put("laozi", 5);
        originalData.put("tangtaizong", 8);
        originalData.put("simaqian", 9);     
        
        
        Map<String, Float> map = new TreeMap(originalData);  // sort by keys
        System.out.println(map);
        

        
    }

    
}

輸出結果: 

{cangjie=5, laozi=5, minghuang=7, simaqian=9, tangtaizong=8}

接下來的介紹另外一種方法,可以當做復習知識點,略微燒腦,這部分的內容轉自:

https://www.javacodegeeks.com/2017/09/java-8-sorting-hashmap-values-ascending-descending-order.html

1、通過調用Map.entrySet()方法獲取條目集

2、通過調用stream()方法獲取條目流

3、用比較器調用排序方法

4、使用Map.Entry.comparingByValue()比較器按值對條目進行排序

5、使用Collect()方法收集結果

6、使用Collectors.to Map()方法在另一個映射中獲取結果。

7、提供LinkedHashMap::new到最后一個參數,強制它返回LinkedHashMap,以保留排序順序。為了按降序排序,只需使用Java 8的Collections.reverse order()或Comparator.reverse()方法反轉Comparator的順序。

PS: 下面是具體的collect框架圖,

實例:

import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
 
import static java.util.stream.Collectors.*;
import static java.util.Map.Entry.*;
 
/*
 * Java Program to sort a Map by values in Java 8
 * 
 */
public class Main {
 
  public static void main(String[] args) throws Exception {
 
    // a Map with string keys and integer values
    Map<String, Integer> budget = new HashMap<>();
    budget.put("clothes", 120);
    budget.put("grocery", 150);
    budget.put("transportation", 100);
    budget.put("utility", 130);
    budget.put("rent", 1150);
    budget.put("miscellneous", 90);
 
    System.out.println("map before sorting: " + budget);
 
    // let's sort this map by values first
    Map<String, Integer> sorted = budget
        .entrySet()
        .stream()
        .sorted(comparingByValue())
        .collect(
            toMap(e -> e.getKey(), e -> e.getValue(), (e1, e2) -> e2,
                LinkedHashMap::new));
 
    System.out.println("map after sorting by values: " + sorted);
 
    // above code can be cleaned a bit by using method reference
    sorted = budget
        .entrySet()
        .stream()
        .sorted(comparingByValue())
        .collect(
            toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e2,
                LinkedHashMap::new));
 
    // now let's sort the map in decreasing order of value
    sorted = budget
        .entrySet()
        .stream()
        .sorted(Collections.reverseOrder(Map.Entry.comparingByValue()))
        .collect(
            toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e2,
                LinkedHashMap::new));
 
    System.out.println("map after sorting by values in descending order: "
        + sorted);
  }
 
}

輸出結果:

map before sorting: {grocery=150, utility=130, miscellneous=90, rent=1150, clothes=120, transportation=100}
map after sorting by values: {miscellneous=90, transportation=100, clothes=120, utility=130, grocery=150, rent=1150}
map after sorting by values in descending order: {rent=1150, grocery=150, utility=130, clothes=120, transportation=100, miscellneous=90}

同時,這里提到比較詳細的步驟,有興趣的可以批閱一下:

https://dzone.com/articles/how-to-sort-a-map-by-value-in-java-8 

 

參考資料:

 https://www.cnblogs.com/heganlin/p/5914892.html

https://tool.oschina.net/uploads/apidocs/jdk-zh/java/util/Map.Entry.html

https://www.javacodegeeks.com/2017/09/java-8-sorting-hashmap-values-ascending-descending-order.html

https://www.geeksforgeeks.org/sorting-a-hashmap-according-to-values/

https://www.java67.com/2015/01/how-to-sort-hashmap-in-java-based-on.html

https://stackoverflow.com/questions/109383/sort-a-mapkey-value-by-values

https://www.jb51.net/article/90660.htm#comments

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM