问题描述
今天写一个实验中使用到了 HashMap
,需要对 HashMap
中的 Double
类型 value
进行排序。
先来看一下要排序的数据集:长度为 1000 的 <Integer,Double>
的 HashMap
:
解决过程
网上搜到了各种按照 HashMap
的 value
进行排序的代码,下面随便贴一个:
(这里我们先使用一组小的虚拟数据进行排序,暂时不使用上面提到的 1000条数据测试)
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.stream.Collectors;
public class MyIntComparator {
public static void main(String[] args) {
Map<Integer, Double> map = new HashMap<Integer, Double>();
map.put(0, 10.0);
map.put(1, 20.0);
map.put(2, 30.0);
map.put(3, 55.0);
map.put(4, 60.0);
map.put(5, 70.2);
map.put(6, 35.8);
List<Map.Entry<Integer, Double>> infoIds = new ArrayList<Map.Entry<Integer, Double>>( map.entrySet());
//排序前
for (int i = 0; i < infoIds.size(); i++) {
String id = infoIds.get(i).toString();
System.out.println(id);
}
//排序
infoIds.sort(new Comparator<Entry<Integer, Double>>() {
@Override
public int compare(Entry<Integer, Double> o1,
Entry<Integer, Double> o2) {
return (int) (o2.getValue() - o1.getValue());
}
});
//排序后
System.out.println("--------------------------排序后:");
for (int i = 0; i < infoIds.size(); i++) {
Entry<Integer, Double> id = infoIds.get(i);
System.out.println(id);
}
}
}
经测试发现,如果对小数点位数较少的数字,如 30.0、40.0 这类数字排序成功:
如果换成多位小数的数据,上述代码排序失败:
map.put(0, 0.030005979496118867);
map.put(1, 0.005852105829598869);
map.put(2, 0.0077810107361007495);
map.put(3, 0.007566500619860167);
map.put(4, 0.015289105190807142);
map.put(5, 0.006420423776411558);
map.put(6, 0.004273848081981763);
排序结果如下,未能成功排序:
经过各种搜索,终于发现了一个有效方法,成功对 HashMap
中 Double
类型的多位小数 value
进行排序:
核心代码:
return (int) ((o2.getValue() - o1.getValue())*10000);
并且可以根据 Double
类型小数点后数字的位数调整上述 10000
中的 0
的个数。
多位小数排序成功:
附一个小问题:Exception in thread “main” java.lang.IllegalArgumentException: Comparison method violates its general contract!
JDK 兼容问题,一个简单的解决方案:VM参数添加如下设置:
-Djava.util.Arrays.useLegacyMergeSort=true
其他具体解决方案可参考链接:https://blog.csdn.net/xvshu/article/details/70153759
参考链接:http://www.360doc.com/content/08/0818/21/59141_1554099.shtml
这样会产生一个问题,注意资料中(“D",23.001)、("E”,23.899),这两个资料在强制类型转换后,都是23,没有办法分辨出浮点数的部分,解决方法不难,先确定要取得的小数点位数是多少,像此范例刚好都是小数点三位,那就取到小数点三位,再强制转换成整敷,这样就可以排出正确大小了。程序修改如下:return(int) ((o2.getValue()-o1.getValue())*1000.0);