public static <K, V extends Comparable<? super V>> List<K> getKeysSortedByValue(Map<K, V> map) {
final int size = map.size();
final List<Map.Entry<K, V>> list = new ArrayList<Map.Entry<K, V>>(size);
list.addAll(map.entrySet());
final ValueComparator<V> cmp = new ValueComparator<V>();
Collections.sort(list, cmp);
final List<K> keys = new ArrayList<K>(size);
for (int i = 0; i < size; i++) {
keys.set(i, list.get(i).getKey());
}
return keys;
}
private static final class ValueComparator<V extends Comparable<? super V>>
implements Comparator<Map.Entry<?, V>> {
public int compare(Map.Entry<?, V> o1, Map.Entry<?, V> o2) {
return o1.getValue().compareTo(o2.getValue());
}
}
public static <K, V extends Comparable<? super V>> List<K> getKeysSortedByValue2(Map<K, V> map) {
final int size = map.size();
final List reusedList = new ArrayList(size);
final List<Map.Entry<K, V>> meView = reusedList;
meView.addAll(map.entrySet());
Collections.sort(meView, SINGLE);
final List<K> keyView = reusedList;
for (int i = 0; i < size; i++) {
keyView.set(i, meView.get(i).getKey());
}
return keyView;
}
private static final Comparator SINGLE = new ValueComparator();
public static class MapStringDoubleComparator implements Comparator {
Map<String, Double> base;
public MapStringDoubleComparator(Map<String, Double> base) {
this.base = base;
}
//note if you want decending in stead of ascending, turn around 1 and -1
public int compare(Object a, Object b) {
if ((Double) base.get(a) == (Double) base.get(b)) {
return 0;
} else if((Double) base.get(a) < (Double) base.get(b)) {
return -1;
}else{
return 1;
}
}
}
public int compare(String a, String b) {
if (base.get(a) > base.get(b)) {
return 1;
} else if (base.get(a) < base.get(b)){
return -1;
}
return 0;
// returning 0 would merge keys
}
20条答案
按热度按时间qni6mghb1#
排序键需要比较器为每个比较查找每个值。一个更具可伸缩性的解决方案将直接使用entryset,因为从那时起,每次比较都可以立即使用该值(尽管我没有用数字来备份)。
下面是这样一个东西的通用版本:
对于上述解决方案,有一些方法可以减少内存循环。例如,创建的第一个arraylist可以被重新用作返回值;这需要抑制一些泛型警告,但对于可重用的库代码来说,这可能是值得的。而且,比较器不必在每次调用时都重新分配。
下面是一个效率更高但吸引力更小的版本:
最后,如果您需要连续地访问已排序的信息(而不是偶尔对其排序一次),则可以使用附加的多重Map。如果你需要更多的细节请告诉我。。。
3gtaxfhh2#
当你有两个相等的项目时,投票最多的答案是不起作用的。树形图遗漏了相等的值。
exmaple:未排序的Map
结果
所以不包括e!!
对我来说,调整比较器效果很好,如果它等于,则不返回0,而是返回-1。
在示例中:
类valuecomparator实现comparator{
Map库;public valuecomparator(map base){this.base=base;}
公共int比较(对象a、对象b){
} }
现在它返回:
未排序Map:
结果:
作为对外星人的回应(2011年11月22日):我使用这个解决方案来处理整数id和名称的Map,但是想法是一样的,所以可能上面的代码是不正确的(我会在测试中编写它并给你正确的代码),这是一个Map排序的代码,基于上面的解决方案:
这是测试类(我刚刚测试了它,它适用于整数、字符串Map:
下面是Map比较器的代码:
这是一个测试用例:
当然,你可以让它更通用,但我只需要一个案例(Map)
xcitsw883#
重要提示:
此代码可以以多种方式中断。如果您打算使用提供的代码,请务必阅读注解并了解其含义。例如,值不能再由其键检索(
get
总是回来null
.)这似乎比前面提到的要容易得多。使用树状图如下:
输出:
kognpnkq4#
给定Map
根据值按升序对Map排序
根据值按设计顺序对Map排序
输出:
{软件=50,技术=70,美国=100,工作=200,机会=200}
{工作=200,机会=200,美国=100,技术=70,软件=50}
lqfhib0f5#
我已经看了给出的答案,但是很多答案都比需要的复杂,或者当几个键有相同的值时删除Map元素。
以下是一个我认为更合适的解决方案:
请注意,Map是从最高值到最低值排序的。
4nkexdtk6#
最佳方法
输出
vmdwslir7#
要通过java 8中的新功能实现这一点:
这些条目使用给定的比较器按其值排序。或者,如果您的值是相互比较的,则不需要显式比较:
返回的列表是调用此方法时给定Map的快照,因此两者都不会反映对另一个方法的后续更改。要实时查看Map,请执行以下操作:
每次迭代时,返回的iterable都会为给定的Map创建一个新的快照,因此除非进行并发修改,否则它将始终反映Map的当前状态。
ezykj2lf8#
这是anthony答案的一个变体,如果存在重复值,则不起作用:
请注意,如何处理空值还很悬而未决。
这种方法的一个重要优点是,它实际上返回一个map,这与这里提供的其他一些解决方案不同。
cgfeq70w9#
使用java 8,您可以使用streams api以一种明显不那么冗长的方式来完成:
irlmq6kh10#
虽然我同意经常需要对Map进行排序可能是一种气味,但我认为下面的代码是在不使用不同数据结构的情况下进行排序的最简单方法。
}
下面是一个令人尴尬的不完整单元测试:
}
结果是map.entry对象的排序列表,您可以从中获得键和值。
35g0bw7111#
创建定制的比较器,并在创建新的treemap对象时使用它。
在主函数中使用以下代码
输出:
py49o6xq12#
Java8提供了一个新的答案:将条目转换为流,并使用map.entry中的comparator组合器:
这将允许您使用按值升序排序的条目。如果要降序,只需反转比较器:
如果值不可比较,则可以传递显式比较器:
然后可以继续使用其他流操作来使用数据。例如,如果您希望新Map中的前10名:
或打印到
System.out
:e7arh2l613#
主要问题。如果您使用第一个答案(google将您带到这里),请更改comparator以添加一个equal子句,否则您将无法从按键排序的Map中获取值:
c9x0cxw014#
使用通用比较器,例如:
qmelpv7a15#
commons集合库包含一个名为treebidimap的解决方案。或者,你可以看看googlecollections的api。它有你可以使用的树形图。
如果你不想使用这些框架。。。它们带有源代码。