如何对HashMap进行排序

问题描述

这个问题从字面上看会有点奇怪,毕竟HashMap是按哈希值存储元素的,每个元素的位置是固定的,所以无法像list一样可以通过索引值list.get(i)去获取元素,由于位置由哈希值确定,也谈不上排序。
但是,问题就在于确实会遇到一些情形,比如我定义了一个map对象

Map<Student, Integer> map = new HashMap<>();

map是由学生类作为key,整型类作为value的,我的toString函数里面,希望它能够按照Integer(实际意义为分数)的大小进行排序,并返回一个按顺序排列的字符串。

比如下面这个map

		Map<Student, Integer> map = new HashMap<>();
		Student a = new Student("a");
		Student b = new Student("b");
		Student c = new Student("c");
		map.put(a, 78);
		map.put(c,60);
		map.put(b,99);

打印map.toString()的结果

{[Student name:a]=78, [Student name:b]=99, [Student name:c]=60}

既不是按照插入顺序,也不是按照我们预期的value大小顺序排列。
所以说直接return map.toString()肯定是不行的,那我怎么能够构造一个字符串表示map,而且是按value大小排列的呢?

解决方案

方法① 首先网上有一些大佬的博客都介绍了用Java8的Streams进行排序,
比如:

map.entrySet().stream().sorted((e1, e2) -> e1.getValue().compareTo(e2.getValue())).forEach(System.out::println);

输完这行代码,然后直接运行,就会神奇地发现控制台打印出了按value顺序排列的map
在这里插入图片描述
然而,这种方法虽然很舒服,但是不能解决我的这个所面临的问题,它不能变成一个可返回的字符串,而是直接打印了出来。

方法② 仍然使用Java8的Streams进行排序,同时借助了LinkedHashMap

Map<Student, Integer> sortedMap = map.entrySet()
	            .stream()
	            .sorted(Map.Entry.comparingByValue())
	            .collect(Collectors
	              .toMap(Map.Entry::getKey,
	                     Map.Entry::getValue,
	                     (e1, e2) -> e1,
	                     LinkedHashMap::new));

这时候,我们打印一下sortedMap

String s = sortedMap.toString();
System.out.println(s);

输出结果:
在这里插入图片描述
这方法也很舒适,直接调用内置方法,就可以排序了,而且只需改一下参数就能按key排序或者是降序排序,十分快捷。

但是,有时候人就比较作,或者面临的情况很specific,比如说,我不希望这个返回的字符串是xx(Student) = xx(成绩)这种形式输出,但是我们知道,map这种类型的toString就是{key1=value1, key2=value2…},如果跑到人家库里面的去改写方法,这不太好…或者自己重新写一个类继承map后又重写toString,会比较麻烦。

所以就有了下面这种比较原始的方法,看上去会比之前两个多花点时间,但是结果上灵活性会更强。

方法③ 这个方法,说起来很直观,一看就懂,一般也能想到,我称之为“土办法”,也就是定义两个列表,keylist和valuelist,然后按value值对valuelist排序,交换valuelist中元素的同时交换keylist中的元素。也就是同时排序的思想。

		String s = "{";
		
		List<Student> keylist = new ArrayList<>();
		List<Integer> valuelist = new ArrayList<>();
		for(Map.Entry<Student, Integer> entry : map.entrySet()) {
			keylist.add(entry.getKey());
			valuelist.add(entry.getValue());
		}//初始化keylist和valuelist
		
		for(int i=0; i<valuelist.size(); i++) {
			int minpos = i;
			Integer min = valuelist.get(i);
			for(int j=i+1; j<valuelist.size(); j++) {
				if(valuelist.get(j).compareTo(min)<0) {
					minpos = j;
					min = valuelist.get(j);
				} 
			}//选择排序(按值排序)
			if(minpos!=i) {
				Integer temp = valuelist.get(i);
				valuelist.set(i, min);
				valuelist.set(minpos, temp);//valuelist排序
				Student templ = keylist.get(i);
				keylist.set(i, keylist.get(minpos));
				keylist.set(minpos, templ);//同时排序keylist
			}
		}
		
		//个性化操作
		for(int i=0; i<keylist.size(); i++) {
			s += keylist.get(i)+" \t对应成绩=";
			s += valuelist.get(i);
			if(i < keylist.size()-1) s+=",\n";
		}
		s+="}";

同时排序使得将原有map分解为:两个索引值对应的list,那么我们就可以按大小顺序对list中的值操作,灵活性会比较高。
打印一下s,输出结果:
在这里插入图片描述

参考链接

如何对HashMap进行排序

  • 5
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
Java中,HashMap是一种无序的数据结构,因此不能直接对其进行排序。但是,可以通过将HashMap中的键值对转换成List,然后对List进行排序来实现对HashMap排序。 具体步骤如下: 1. 将HashMap中的键值对转换成List,可以使用HashMap中的entrySet()方法,将其转换成Set,再使用ArrayList的构造函数将其转换成List。 2. 对List进行排序,可以使用Collections类中的sort()方法,并指定排序规则。这里可以使用Comparator接口的实现类来指定排序规则,也可以直接对值或键进行排序。 3. 将排序后的List转换回HashMap,可以使用HashMap的构造函数,并传入排序后的List作为参数。 以下是示例代码: ```java HashMap<String, Integer> map = new HashMap<>(); map.put("c", 3); map.put("a", 1); map.put("d", 4); map.put("b", 2); 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.getKey().compareTo(o2.getKey()); } }); HashMap<String, Integer> sortedMap = new LinkedHashMap<>(); for (Map.Entry<String, Integer> entry : list) { sortedMap.put(entry.getKey(), entry.getValue()); } System.out.println(sortedMap); // 输出:{a=1, b=2, c=3, d=4} ``` 在示例代码中,通过将HashMap中的键值对转换成List,并使用Collections类的sort()方法对List进行排序,指定了按照键的升序排序规则。最后,将排序后的List转换回HashMap。注意,这里使用了LinkedHashMap,是因为HashMap是无序的,如果想保留排序结果,需要使用有序的Map。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值