Java中如何对HashMap进行排序


=Start=

缘由:

Java中HashMap的值是没有顺序的,它是按照key的HashCode来实现的。对于这个无序的HashMap我们要怎么来实现排序呢?这里就整理总结一下,方便以后查阅、参考。

正文:

参考解答:

先说结论,如果着急的话可以先看这个/只看这个就够:

Java中对 HashMap 进行排序的一般步骤就是:

1、先根据 HashMap 的内容生成 list ;
2、再调用 Collections.sort(list[, new Comparator]) 对 list 进行就地排序;
2.1、 内部进行的比较一般是通过 .compareTo() 方法进行的,但是也可以自行修改「大于返回1,小于返回-1,等于返回0」;
3、 如果只要排序后的结果的话,可以直接用 list ;如果还要一个map的话,就新建一个LinkedHashMap来存放list的结果。


Java中的原生排序方法整理:

  • 对基本类型排序 # Arrays.sort()
  • 对对象数组排序 # 则要自己实现 java.util.Comparator 接口
//1. 数字排序
int[] intArray = new int[] { 4, 1, 3, -23 };
Arrays.sort(intArray);
System.out.println(Arrays.toString(intArray));
//输出: [-23, 1, 3, 4]

//2. 字符串排序,先大写后小写
String[] strArray = new String[] { "z", "a", "C" };
System.out.println(Arrays.toString(strArray));
//输出: [z, a, C]
Arrays.sort(strArray);
System.out.println(Arrays.toString(strArray));
//输出: [C, a, z]

//3. 严格按字母表顺序排序,也就是忽略大小写排序 Case-insensitive sort
Arrays.sort(strArray, String.CASE_INSENSITIVE_ORDER);
System.out.println(Arrays.toString(strArray));
//输出: [a, C, z]

//4. 反向排序, Reverse-order sort
Arrays.sort(strArray, Collections.reverseOrder());
System.out.println(Arrays.toString(strArray));
//输出: [z, a, C]

//5. 忽略大小写反向排序 Case-insensitive reverse-order sort
Arrays.sort(strArray, String.CASE_INSENSITIVE_ORDER);
Collections.reverse(Arrays.asList(strArray));
System.out.println(Arrays.toString(strArray));
//输出: [z, C, a]

Java中打印数组的方法,参考「链接」。


再放整理后的代码:

package com.ixyzero.learn.misc;

import java.util.*;
import java.util.Map.Entry;

/**
 * https://stackoverflow.com/questions/8119366/sorting-hashmap-by-values/13913206#13913206
 */
public class SortMapByValue
{
    public static boolean ASC = true;
    public static boolean DESC = false;

    public static void main(String[] args)
    {
        // Creating dummy unsorted map
        Map<String, Integer> unsortedMap = new HashMap<>();
        unsortedMap.put("B", 55);
        unsortedMap.put("A", 80);
        unsortedMap.put("D", 20);
        unsortedMap.put("C", 70);

        System.out.println("Before sorting......");
        printMap(unsortedMap);

        System.out.println("\nAfter sorting ascending order......");
        Map<String, Integer> sortedMapAsc = sortByValueComparator(unsortedMap, ASC);
        printMap(sortedMapAsc);

        System.out.println("\nAfter sorting descending order......");
        Map<String, Integer> sortedMapDesc = sortByValueComparator(unsortedMap, DESC);
        printMap(sortedMapDesc);

        System.out.println("\nAfter sorting descending order by key......");
        Map<String, Integer> sortedKeyMapDesc = sortByKeyComparator(sortedMapAsc, DESC);
        printMap(sortedKeyMapDesc);
    }

    private static Map<String, Integer> sortByKeyComparator(Map<String, Integer> unsortedMap, final boolean order)
    {

        List<Map.Entry<String, Integer>> list = new LinkedList<>(unsortedMap.entrySet());

        // Sorting the list based on values
        Collections.sort(list, new Comparator<Map.Entry<String, Integer>>() {
            public int compare(Map.Entry<String, Integer> o1, Map.Entry<String, Integer> o2) {
                if (order) {
                    return o1.getKey().toString().compareTo(o2.getKey().toString());
                } else {
                    return o2.getKey().toString().compareTo(o1.getKey().toString());
                }
            }
        });

        // Maintaining insertion order with the help of LinkedList
        Map<String, Integer> sortedMap = new LinkedHashMap<>();
        for (Map.Entry<String, Integer> entry : list) {
            sortedMap.put(entry.getKey(), entry.getValue());
        }

        return sortedMap;
    }


    private static Map<String, Integer> sortByValueComparator(Map<String, Integer> unsortedMap, final boolean order)
    {

        List<Map.Entry<String, Integer>> list = new LinkedList<>(unsortedMap.entrySet());

        // Sorting the list based on values
        Collections.sort(list, new Comparator<Map.Entry<String, Integer>>() {
            public int compare(Map.Entry<String, Integer> o1, Map.Entry<String, Integer> o2) {
                if (order) {
                    return o1.getValue().compareTo(o2.getValue());
                } else {
                    return o2.getValue().compareTo(o1.getValue());
                }
            }
        });

        // Maintaining insertion order with the help of LinkedList
        Map<String, Integer> sortedMap = new LinkedHashMap<>();
        for (Map.Entry<String, Integer> entry : list) {
            sortedMap.put(entry.getKey(), entry.getValue());
        }

        return sortedMap;
    }

    public static void printMap(Map<String, Integer> map)
    {
        for (Entry<String, Integer> entry : map.entrySet()) {
            System.out.println("Key: " + entry.getKey() + "\tValue: "+ entry.getValue());
        }
    }
}

 

参考链接:

=END=


《 “Java中如何对HashMap进行排序” 》 有 16 条评论

  1. java集合遍历的几种方式总结及比较
    https://www.cnblogs.com/leskang/p/6031282.html
    `
    集合类的通用遍历方式,用迭代器迭代:
    Iterator it = list.iterator();
    while(it.hasNext()) {
    Object obj = it.next();
    }

    Map的几种遍历方式
    List的几种遍历方式
    数据元素是怎样在内存中存放的?
    每个遍历方法的实现原理是什么?
    各遍历方式对于不同的存储方式,性能如何?
    各遍历方式的适用于什么场合?

    Java的最佳实践是什么?
    if (list instanceof RandomAccess) {
    //使用传统的for循环遍历。
    } else {
    //使用Iterator或者foreach。
    }
    `

  2. Java中如何打印 byte[]
    https://stackoverflow.com/questions/6463580/how-to-print-the-data-in-byte-array-as-characters/6463665#6463665
    `
    byte[] byteArray = new byte[] { -1, -128, 1, 127 };
    System.out.println(Arrays.toString(byteArray));
    `
    Java中打印数组的最简单方法
    https://stackoverflow.com/questions/409784/whats-the-simplest-way-to-print-a-java-array
    `
    # 简单数组(各种类型都可以,比如 int/double/String/byte)
    String[] array = new String[] {“John”, “Mary”, “Bob”};
    System.out.println(Arrays.toString(array));

    # 嵌套数组
    String[][] deepArray = new String[][] {{“John”, “Mary”}, {“Alice”, “Bob”}};
    System.out.println(Arrays.toString(deepArray));
    // output: [[Ljava.lang.String;@106d69c, [Ljava.lang.String;@52e922]
    System.out.println(Arrays.deepToString(deepArray));
    // [[John, Mary], [Alice, Bob]]
    `

  3. JAVA构造MAP并初始化MAP
    https://stackoverflow.com/questions/6802483/how-to-directly-initialize-a-hashmap-in-a-literal-way
    https://stackoverflow.com/questions/507602/how-can-i-initialise-a-static-map
    https://blog.csdn.net/dujianxiong/article/details/54849079
    `
    方法一:先 new 创建,然后逐步 put 填充
    Map myMap = new HashMap();
    myMap.put(“a”, “b”);
    myMap.put(“c”, “d”);

    方法二:双括号初始化(匿名内部类)
    Map map = new HashMap() {
    {
    put(“name”, “test”);
    put(“age”, “20”);
    }
    };
    `

  4. Java中利用HashMap做去重计数
    https://www.mkyong.com/java/how-to-count-duplicated-items-in-java-list/
    `
    Map map = new HashMap();

    for (String temp : list) {
    Integer count = map.get(temp);
    map.put(temp, (count == null) ? 1 : count + 1);
    }
    `
    Java program to count the occurrence of each character in a string using Hashmap
    https://www.geeksforgeeks.org/java-program-to-count-the-occurrence-of-each-character-in-a-string-using-hashmap/

    Map统计去重复统计重复出现的次数
    https://blog.csdn.net/qq_40195958/article/details/78904634

  5. java Map集合嵌套,value为Map和value为List
    https://blog.csdn.net/mustbehard/article/details/17310043
    `
    Map<String,Map> outMap = new HashMap<String,Map>();
    Map innerMap1 = new HashMap();
    Map innerMap2 = new HashMap();

    /*
    * 要使用下面这种方式,先把集合定义好,
    * 把映射关系设置好,再去给集合添加元素
    */
    outMap.put(“map1”, innerMap1);
    outMap.put(“map2”, innerMap2);

    innerMap1.put(“01”, “zhangsan”);
    innerMap1.put(“02”, “lisi”);

    innerMap2.put(“01”, “zhaoliu”);
    innerMap2.put(“02”, “zhouqi”);
    `
    java中HashMap的嵌套用例
    https://blog.csdn.net/euller/article/details/70233062

  6. Java Map集合 遍历 五种方式(包含 Lambda 表达式遍历)
    https://www.cnblogs.com/miracle-luna/p/10995132.html
    `
    // 第五种遍历方式(JDK 1.8支持的 Lambda 表达式,强烈推荐!!!)
    System.out.println(“\n第五种遍历方式:通过 Lambda 表达式,遍历 Key 和 Value”);
    map.forEach((key, value) -> {
    System.out.println(“Key: ” + key + “, Value: ” + value);
    });
    `
    List集合 遍历 四种方式(包含 Lambda 表达式遍历)
    https://www.cnblogs.com/miracle-luna/p/10995400.html

    Enum枚举 遍历判断 四种方式(包括 Lambda 表达式过滤)
    https://www.cnblogs.com/miracle-luna/p/10995539.html

    Array数组 遍历 四种方式(包含 Lambda 表达式遍历)
    https://www.cnblogs.com/miracle-luna/p/10995469.html

  7. https://stackoverflow.com/questions/934775/changing-value-after-its-placed-in-hashmap-changes-whats-inside-hashmap/30859349#30859349
    https://blog.csdn.net/sinat_29384657/article/details/52933817
    `
    # map合并
    Map 的 .putAll() 方法可以合并两个Map,只不过如果有相同的key那么用后面的覆盖前面的值

    # map赋值
    Java中用mapA对mapB进行赋值时,不要使用:
    mapB = mapA; // 错误的方式
    的方式;
    而应该使用先clear然后putAll的方式:
    mapB.clear();
    mapB.putAll(mapA);
    `

  8. Java中(嵌套)map的pretty-print打印
    Multi-line pretty-printing of (nested) collections in Java
    https://stackoverflow.com/questions/15171699/multi-line-pretty-printing-of-nested-collections-in-java
    https://stackoverflow.com/questions/10120273/pretty-print-a-map-in-java/30659764#30659764
    `
    import org.json.JSONObject;
    System.out.println(new JSONObject(myMap).toString(2));

    // 本地测试打印还行,但是如果希望赋值给某个变量就不太好用了
    MapUtils.debugPrint(System.out, “myMap”, myMap);
    `
    https://mvnrepository.com/artifact/org.apache.commons/commons-collections4

  9. Java中如何找出 hashmap 中 value 最大的那对 k-v 键值对?
    https://stackoverflow.com/questions/5911174/finding-key-associated-with-max-value-in-a-java-map
    https://stackoverflow.com/questions/49470423/get-the-highest-values-in-a-hashmap-in-java
    https://stackoverflow.com/questions/7498751/get-the-keys-with-the-biggest-values-from-a-hashmap
    `
    import java.util.*;

    public class HashmapTest {
    public static void main(String[] args) {
    Map map = new HashMap();
    map.put(“name1”, 3);
    map.put(“name2”, 14);
    map.put(“name3”, 4);
    map.put(“name4”, 14);
    map.put(“name5”, 2);
    map.put(“name6”, 6);
    System.out.println(map);

    int max = Collections.max(map.values());
    List keys = new ArrayList();
    for (Map.Entry entry : map.entrySet()) {
    if (entry.getValue()==max) {
    keys.add(entry.getKey());
    }
    }
    System.out.println(keys);

    }
    }
    `

  10. 在 Java 中初始化 List 的五种方法
    https://blog.csdn.net/YZBYZZ/article/details/83722346
    https://juejin.im/post/5bddcee3e51d4520b6639663
    `
    1. 构造 List 后使用 List.add 初始化
    List stringList = new LinkedList();
    stringList.add(“a”);
    stringList.add(“b”);
    stringList.add(“c”);

    2. 使用 {{}} 双括号语法
    List stringList = new LinkedList(){{
    add(“a”);
    add(“b”);
    add(“c”);
    }};

    3. 使用 Arrays.asList #如果只是用来初始化常量,一些注意事项可以不用考虑
    List stringList = Arrays.asList(“a”, “b”, “c”);

    4. 使用 Stream (JDK8)
    List list = Stream.of(“a”, “b”, “c”).collect(Collectors.toList());

    5. 使用 Lists (JDK9)
    List list = Lists.newArrayList(“a”, “b”, “c”);
    这个和 Arrays.asList 一样简洁清晰。
    `

  11. Java中 HashMap 的初始化方法整理
    `
    # 简而言之,下面这两种是最通用也最好理解的方案,其它的要么是非常规方式 Collections 要么是有 Java 8/9 的要求,或者是需要额外的依赖(比如:Guava),一般情况下以下两种就能满足。

    1. 在 static 语句块中初始化

    public static Map articleMapOne = new HashMap();
    static {
    articleMapOne.put(“ar01”, “Intro to Map”);
    articleMapOne.put(“ar02”, “Some article”);
    }

    2. 双括号语法

    Map doubleBraceMap = new HashMap() {{
    put(“key1”, “value1”);
    put(“key2”, “value2”);
    }};
    `

    How to directly initialize a HashMap (in a literal way)?
    https://stackoverflow.com/questions/6802483/how-to-directly-initialize-a-hashmap-in-a-literal-way

    Initialize a HashMap in Java
    https://www.baeldung.com/java-initialize-hashmap
    https://github.com/eugenp/tutorials/tree/master/java-collections-maps-2

    Java 中 HashMap 初始化时赋值
    https://www.cnblogs.com/pejsidney/p/9235343.html

  12. 面试官再问你 HashMap 底层原理,就把这篇文章甩给他看
    https://mp.weixin.qq.com/s/fA4ohy2iRwWWRIRpkR0HLA
    `
    本篇文章主要包括以下内容:
    · HashMap 的存储结构
    · 常用变量说明,如加载因子等
    · HashMap 的四个构造函数
    · tableSizeFor()方法及作用
    · put()方法详解
    · hash()方法,以及避免哈希碰撞的原理
    · resize()扩容机制及原理
    · get()方法
    · 为什么HashMap链表会形成死循环,JDK1.8做了哪些优化

    # HashMap存储结构
    这里需要区分一下,JDK1.7和 JDK1.8之后的 HashMap 存储结构。在JDK1.7及之前,是用【数组】加【链表】的方式存储的。

    但是,众所周知,当链表的长度特别长的时候,查询效率将直线下降,查询的时间复杂度为 O(n)。因此,JDK1.8 把它设计为达到一个特定的阈值之后,就将【链表】转化为【红黑树】。
    由于红黑树是一个自平衡的二叉搜索树,因此可以使查询的时间复杂度降为O(logn)。
    `

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注