Map的排序

本文对比了Java中HashMap、LinkedHashMap与TreeMap三种Map集合的特点与应用场景。重点介绍了它们如何保持插入顺序、自然排序及自定义排序,并通过实例演示了不同Map类型的输出结果。

  今天工作中需要用到一个保持插入顺序的键值对的数据结构。遂想到了Map中的 JDK中map的LinkedHashMap 能满足需要。顺便做了下面的整理。

 

   排序都是依据key来排序的。如果要依据Value来排序,需要自己来实现相关的Map类,有兴趣的可以试试看。

 

   LinkedHashMap 会保持插入时候的顺序,但是相同的key插入多次,默认以第一次插入的顺序为准,除非将accessOrder设置为true,则以最后一次插入的顺序为准

           LinkedHashMap<String,String> map=new LinkedHashMap<String,String>();
	    map.put("abc", "11");
	    map.put("bbc", "11");
	    map.put("cac", "11");
	    map.put("dbc", "11");
	    map.put("aba", "11");
	    
	    for(Map.Entry<String, String> entry:map.entrySet()){
	        System.out.println(entry.getKey() +" : "+entry.getValue());
	    }

   结果:

  abc : 11

  bbc : 11

  cac : 11

  dbc : 11

  aba : 11

 

   HashMap不保证映射的顺序,特别是它不保证该顺序恒久不变

           HashMap<String,String> map=new HashMap<String,String>();
	    map.put("abc", "11");
	    map.put("bbc", "11");
	    map.put("cac", "11");
	    map.put("dbc", "11");
	    map.put("aba", "11");
	    
	    for(Map.Entry<String, String> entry:map.entrySet()){
	        System.out.println(entry.getKey() +" : "+entry.getValue());
	    }

   结果:

   aba : 11

   cac : 11

   dbc : 11

   abc : 11

   bbc : 11

 

   TreeMap如果不实现自定义的Comparator接口,则按照自然顺序进行排序。内部基于红黑树的数据结构实现。

    

           TreeMap<String,String> map=new TreeMap<String,String>();
	    map.put("abc", "11");
	    map.put("bbc", "11");
	    map.put("cac", "11");
	    map.put("dbc", "11");
	    map.put("aba", "11");
	    
	    for(Map.Entry<String, String> entry:map.entrySet()){
	        System.out.println(entry.getKey() +" : "+entry.getValue());
	    }

   结果:

   aba : 11

   abc : 11

   bbc : 11

   cac : 11

   dbc : 11

 

   

 TreeMap<String,String> map=new TreeMap<String,String>(new Comparator<String>(){

            @Override
            public int compare(String o1, String o2) {
                return o2.compareTo(o1);
            }
	    });
	    map.put("abc", "11");
	    map.put("bbc", "11");
	    map.put("cac", "11");
	    map.put("dbc", "11");
	    map.put("aba", "11");
	    
	    for(Map.Entry<String, String> entry:map.entrySet()){
	        System.out.println(entry.getKey() +" : "+entry.getValue());
	    }

    结果:

    dbc : 11

cac : 11

bbc : 11

abc : 11

aba : 11

 

<think>我们正在讨论JavaMap排序方法。根据引用内容,Map排序主要分为两种:按键排序和按值排序。同时,我们还需要了解Map的不同实现类(如HashMap、TreeMap、LinkedHashMap)在有序性上的区别。 引用[1]提到: - HashMap: 无序,基于哈希表实现。 - TreeMap: 有序,基于红黑树,可以按自然顺序或自定义比较器排序。 - LinkedHashMap: 保持插入顺序或访问顺序(LRU)。 引用[2]和[4]展示了如何对Map按值排序:将Map的entrySet转成List,然后使用Collections.sort并传入自定义比较器(按值比较),最后将排序后的List放入一个有序Map(如LinkedHashMap)中。 因此,我们可以总结如下: 一、Map排序方法: 1. 按键排序: - 使用TreeMap:它会自动按键的自然顺序(或构造时提供的Comparator)排序。 - 示例代码: ```java Map<String, String> map = new HashMap<>(); // 添加一些键值对 Map<String, String> sortedMapByKey = new TreeMap<>(map); ``` 2. 按值排序: - 步骤: a. 将Map的entrySet转换成List。 b. 使用Collections.sort对List进行排序,自定义比较器(按值比较)。 c. 将排序后的List放入LinkedHashMap以保持顺序。 - 示例代码(Java 8之前): ```java public static <K, V extends Comparable<? super V>> Map<K, V> sortByValue(Map<K, V> map) { List<Map.Entry<K, V>> list = new ArrayList<>(map.entrySet()); Collections.sort(list, new Comparator<Map.Entry<K, V>>() { @Override public int compare(Map.Entry<K, V> o1, Map.Entry<K, V> o2) { return o1.getValue().compareTo(o2.getValue()); // 升序 } }); Map<K, V> result = new LinkedHashMap<>(); for (Map.Entry<K, V> entry : list) { result.put(entry.getKey(), entry.getValue()); } return result; } ``` 二、Java 8及以后的按值排序方法(更简洁): - 使用Stream API: ```java Map<String, String> sortedMap = map.entrySet().stream() .sorted(Map.Entry.comparingByValue()) // 按值升序 .collect(Collectors.toMap( Map.Entry::getKey, Map.Entry::getValue, (oldValue, newValue) -> oldValue, // 合并函数,如果有重复键,保留旧值(在按值排序中一般不会重复键冲突,但需要提供) LinkedHashMap::new // 使用LinkedHashMap保持顺序 )); ``` 三、自定义排序规则: - 无论是按键还是按值,都可以通过传入自定义的Comparator来实现。 - 例如,按键的降序: ```java // 使用TreeMap Map<String, String> sortedByKeyDesc = new TreeMap<>(Comparator.reverseOrder()); sortedByKeyDesc.putAll(map); ``` - 按值的降序: ```java // 使用Stream API Map<String, String> sortedMapDesc = map.entrySet().stream() .sorted(Map.Entry.<String, String>comparingByValue().reversed()) .collect(Collectors.toMap( Map.Entry::getKey, Map.Entry::getValue, (oldValue, newValue) -> oldValue, LinkedHashMap::new )); ``` 四、注意事项: - HashMap本身是无序的,而TreeMap在插入时就会按键排序,LinkedHashMap则保持插入或访问顺序。 - 按值排序通常需要将Map转换为List再排序,然后放入有序Map中。 五、性能考虑: - 如果经常需要按顺序访问,使用TreeMap(按键排序)更高效。 - 如果只是偶尔需要排序,使用按值排序的方法(转换List排序)即可。 下面是一个完整的示例,展示如何按键排序和按值排序(包括升序和降序): ```java import java.util.*; import java.util.stream.Collectors; public class MapSortExample { public static void main(String[] args) { Map<String, Integer> map = new HashMap<>(); map.put("Alice", 90); map.put("Bob", 85); map.put("Charlie", 95); map.put("David", 88); // 1. 按键升序(TreeMapMap<String, Integer> sortedByKeyAsc = new TreeMap<>(map); System.out.println("按键升序: " + sortedByKeyAsc); // 2. 按键降序(TreeMap + Comparator.reverseOrder()) Map<String, Integer> sortedByKeyDesc = new TreeMap<>(Comparator.reverseOrder()); sortedByKeyDesc.putAll(map); System.out.println("按键降序: " + sortedByKeyDesc); // 3. 按值升序(使用Stream API) Map<String, Integer> sortedByValueAsc = map.entrySet().stream() .sorted(Map.Entry.comparingByValue()) .collect(Collectors.toMap( Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new )); System.out.println("按值升序: " + sortedByValueAsc); // 4. 按值降序(使用Stream API) Map<String, Integer> sortedByValueDesc = map.entrySet().stream() .sorted(Map.Entry.<String, Integer>comparingByValue().reversed()) .collect(Collectors.toMap( Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new )); System.out.println("按值降序: " + sortedByValueDesc); } } ``` 输出: ``` 按键升序: {Alice=90, Bob=85, Charlie=95, David=88} 按键降序: {David=88, Charlie=95, Bob=85, Alice=90} 按值升序: {Bob=85, David=88, Alice=90, Charlie=95} 按值降序: {Charlie=95, Alice=90, David=88, Bob=85} ``` 六、引用说明: 根据引用[1]和[2],我们了解到Map的几种实现类的有序性,以及按值排序的方法。引用[4]提供了一个按值排序的通用方法(使用List和Collections.sort),我们在此基础上结合Java 8的Stream API给出了更现代的写法。 相关问题: §§相关问题§§ 1. Java中HashMap和TreeMap的主要区别是什么? 2. 如何在Java中实现Map的按值排序(使用Java 8 Stream)? 3. 如何对Map的键使用自定义对象?需要注意什么? </think> ### JavaMap排序方法详解 在Java中,Map排序主要分为**按键排序**和**按值排序**两种方式。根据Map实现类的特性不同,排序方法也有所差异。以下是详细实现方法: #### 一、Map实现类的有序性区别 | 实现类 | 有序性 | 排序原理 | |--------------|---------------------------|-----------------------------| | `HashMap` | 无序 | 基于哈希桶,遍历顺序不固定 | | `TreeMap` | 按键自然排序 | 红黑树结构,自动排序[^1] | | `LinkedHashMap` | 保持插入/访问顺序 | 双向链表维护顺序 | #### 二、按键排序方法 1. **使用TreeMap自动排序** ```java Map<String, Integer> map = new HashMap<>(); map.put("Orange", 5); map.put("Apple", 3); map.put("Banana", 2); // 按键升序排序 Map<String, Integer> sortedMap = new TreeMap<>(map); System.out.println(sortedMap); // {Apple=3, Banana=2, Orange=5} // 按键降序排序 Map<String, Integer> reverseMap = new TreeMap<>(Comparator.reverseOrder()); reverseMap.putAll(map); System.out.println(reverseMap); // {Orange=5, Banana=2, Apple=3} ``` 2. **自定义排序规则** ```java // 按字符串长度排序 Map<String, Integer> customSort = new TreeMap<>( (s1, s2) -> s1.length() - s2.length() ); customSort.putAll(map); System.out.println(customSort); // {Apple=3, Orange=5, Banana=2} ``` #### 三、按值排序方法 1. **传统方法(Java 8之前)** ```java List<Map.Entry<String, Integer>> list = new ArrayList<>(map.entrySet()); Collections.sort(list, new Comparator<Map.Entry<String, Integer>>() { public int compare(Map.Entry<String, Integer> o1, Map.Entry<String, Integer> o2) { return o1.getValue() - o2.getValue(); // 按值升序 } }); Map<String, Integer> result = new LinkedHashMap<>(); for (Map.Entry<String, Integer> entry : list) { result.put(entry.getKey(), entry.getValue()); } System.out.println(result); // {Banana=2, Apple=3, Orange=5} ``` 2. **Java 8 Stream API方法** ```java Map<String, Integer> sortedByValue = map.entrySet().stream() .sorted(Map.Entry.comparingByValue()) // 按值升序 .collect(Collectors.toMap( Map.Entry::getKey, Map.Entry::getValue, (oldVal, newVal) -> oldVal, LinkedHashMap::new // 保持排序顺序 )); System.out.println(sortedByValue); // {Banana=2, Apple=3, Orange=5} // 按值降序 Map<String, Integer> reverseByValue = map.entrySet().stream() .sorted(Map.Entry.<String, Integer>comparingByValue().reversed()) .collect(Collectors.toMap(...)); // 同上 ``` #### 四、复合排序(键值组合) ```java // 先按值降序,值相同按键升序 Map<String, Integer> complexSort = map.entrySet().stream() .sorted(Map.Entry .<String, Integer>comparingByValue().reversed() .thenComparing(Map.Entry.comparingByKey()) ) .collect(Collectors.toMap(...)); ``` #### 五、性能比较 | 方法 | 时间复杂度 | 适用场景 | |---------------|----------|----------------------------| | `TreeMap` | O(n log n) | 需要频繁按键排序 | | `LinkedHashMap` | O(n) | 需要保持插入顺序 | | Stream排序 | O(n log n) | 需要复杂排序逻辑 | > **最佳实践**: > - 需要自动排序 → 使用`TreeMap` > - 需要保持插入顺序 → 使用`LinkedHashMap` > - 需要按值排序 → 使用Stream API + `LinkedHashMap` > - 大数据量排序 → 避免频繁创建中间集合 #### 六、注意事项 1. 排序时需处理`null`值(`Comparator.nullsFirst()`) 2. 自定义对象作为键时需重写`equals()`和`hashCode()` 3. 多线程环境使用`ConcurrentSkipListMap`替代`TreeMap`
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值