I am relatively new to Java, and often find that I need to sort a Map<Key, Value>
on the values.
我对Java比较陌生,经常发现我需要对Map
Since the values are not unique, I find myself converting the keySet
into an array
, and sorting that array through array sort with a custom comparator that sorts on the value associated with the key.
由于这些值不是惟一的,所以我发现自己将keySet转换为一个数组,并通过数组排序来对该数组进行排序,并使用自定义的comparator对与该键关联的值进行排序。
Is there an easier way?
有更简单的方法吗?
45 个解决方案
#1
746
Here's a generic-friendly version:
这里有一个generic-friendly版本:
public class MapUtil {
public static <K, V extends Comparable<? super V>> Map<K, V> sortByValue(Map<K, V> map) {
List<Entry<K, V>> list = new ArrayList<>(map.entrySet());
list.sort(Entry.comparingByValue());
Map<K, V> result = new LinkedHashMap<>();
for (Entry<K, V> entry : list) {
result.put(entry.getKey(), entry.getValue());
}
return result;
}
}
#2
400
Important note:
This code can break in multiple ways. If you intend to use the code provided, be sure to read the comments as well to be aware of the implications. For example, values can no longer be retrieved by their key. (get
always returns null
.)
此代码可以以多种方式中断。如果您打算使用所提供的代码,请务必阅读注释并了解其含义。例如,值不能再由其键检索。(总是返回null。)
It seems much easier than all of the foregoing. Use a TreeMap as follows:
这似乎比前面所有的都容易。使用TreeMap如下:
public class Testing {
public static void main(String[] args) {
HashMap<String, Double> map = new HashMap<String, Double>();
ValueComparator bvc = new ValueComparator(map);
TreeMap<String, Double> sorted_map = new TreeMap<String, Double>(bvc);
map.put("A", 99.5);
map.put("B", 67.4);
map.put("C", 67.4);
map.put("D", 67.3);
System.out.println("unsorted map: " + map);
sorted_map.putAll(map);
System.out.println("results: " + sorted_map);
}
}
class ValueComparator implements Comparator<String> {
Map<String, Double> base;
public ValueComparator(Map<String, Double> base) {
this.base = base;
}
// Note: this comparator imposes orderings that are inconsistent with
// equals.
public int compare(String a, String b) {
if (base.get(a) >= base.get(b)) {
return -1;
} else {
return 1;
} // returning 0 would merge keys
}
}
Output:
输出:
unsorted map: {D=67.3, A=99.5, B=67.4, C=67.4}
results: {D=67.3, B=67.4, C=67.4, A=99.5}
#3
206
Three 1-line answers...
三种1条线的答案……
I would use Google Collections Guava to do this - if your values are Comparable
then you can use
我将使用谷歌集合Guava来做这个——如果你的值是可比较的,那么你可以使用。
valueComparator = Ordering.natural().onResultOf(Functions.forMap(map))
Which will create a function (object) for the map [that takes any of the keys as input, returning the respective value], and then apply natural (comparable) ordering to them [the values].
它将为映射创建一个函数(对象),它将任何键作为输入,返回相应的值),然后将自然(可比较的)排序应用到它们(值)。
If they're not comparable, then you'll need to do something along the lines of
如果它们不具有可比性,那么你就需要沿着这条线做一些事情。
valueComparator = Ordering.from(comparator).onResultOf(Functions.forMap(map))
These may be applied to a TreeMap (as Ordering
extends Comparator
), or a LinkedHashMap after some sorting
这些可以应用于TreeMap(如订购扩展比较器),或在一些排序之后的LinkedHashMap。
NB: If you are going to use a TreeMap, remember that if a comparison == 0, then the item is already in the list (which will happen if you have multiple values that compare the same). To alleviate this, you could add your key to the comparator like so (presuming that your keys and values are Comparable
):
NB:如果您打算使用TreeMap,请记住,如果比较== 0,那么该项就已经在列表中(如果您有多个比较相同的值,则会发生这种情况)。为了缓解这种情况,您可以将您的密钥添加到comparator(假定您的键和值是可比较的):
valueComparator = Ordering.natural().onResultOf(Functions.forMap(map)).compound(Ordering.natural())
= Apply natural ordering to the value mapped by the key, and compound that with the natural ordering of the key
=将自然排序应用于键映射的值,并将其与键的自然排序结合起来。
Note that this will still not work if your keys compare to 0, but this should be sufficient for most comparable
items (as hashCode
, equals
and compareTo
are often in sync...)
请注意,如果您的键与0比较,这仍然是无效的,但是对于大多数可比较的项来说,这应该足够了(因为hashCode、equals和compareTo通常是同步的…)
See Ordering.onResultOf() and Functions.forMap().
看到Ordering.onResultOf()和Functions.forMap()。
Implementation
So now that we've got a comparator that does what we want, we need to get a result from it.
现在我们有了一个比较器它可以做我们想要的,我们需要得到它的结果。
map = ImmutableSortedMap.copyOf(myOriginalMap, valueComparator);
Now this will most likely work work, but:
现在这很可能是工作,但是:
- needs to be done given a complete finished map
- 需要完成一张完整的地图。
- Don't try the comparators above on a
TreeMap
; there's no point trying to compare an inserted key when it doesn't have a value until after the put, i.e., it will break really fast - 不要在TreeMap上尝试以上的比较器;当插入键没有值的时候,尝试比较插入的键是没有意义的,比如。它会很快断裂。
Point 1 is a bit of a deal-breaker for me; google collections is incredibly lazy (which is good: you can do pretty much every operation in an instant; the real work is done when you start using the result), and this requires copying a whole map!
第一点对我来说是一种破坏;谷歌集合非常懒惰(这很好:你可以在瞬间完成几乎所有的操作;真正的工作是在您开始使用结果时完成的),而这需要复制整个映射!
"Full" answer/Live sorted map by values
Don't worry though; if you were obsessed enough with having a "live" map sorted in this manner, you could solve not one but both(!) of the above issues with something crazy like the following:
不要担心;如果你对“活的”地图有足够的兴趣,你可以用以下的疯狂的方式来解决上述问题:
Note: This has changed significantly in June 2012 - the previous code could never work: an internal HashMap is required to lookup the values without creating an infinite loop between the TreeMap.get()
-> compare()
and compare()
-> get()
注意:这在2012年6月发生了显著的变化——以前的代码无法工作:需要一个内部HashMap来查找值,而无需在TreeMap.get()中创建一个无限循环。
import static org.junit.Assert.assertEquals;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
import com.google.common.base.Functions;
import com.google.common.collect.Ordering;
class ValueComparableMap<K extends Comparable<K>,V> extends TreeMap<K,V> {
//A map for doing lookups on the keys for comparison so we don't get infinite loops
private final Map<K, V> valueMap;
ValueComparableMap(final Ordering<? super V> partialValueOrdering) {
this(partialValueOrdering, new HashMap<K,V>());
}
private ValueComparableMap(Ordering<? super V> partialValueOrdering,
HashMap<K, V> valueMap) {
super(partialValueOrdering //Apply the value ordering
.onResultOf(Functions.forMap(valueMap)) //On the result of getting the value for the key from the map
.compound(Ordering.natural())); //as well as ensuring that the keys don't get clobbered
this.valueMap = valueMap;
}
public V put(K k, V v) {
if (valueMap.containsKey(k)){
//remove the key in the sorted set before adding the key again
remove(k);
}
valueMap.put(k,v); //To get "real" unsorted values for the comparator
return super.put(k, v); //Put it in value order
}
public static void main(String[] args){
TreeMap<String, Integer> map = new ValueComparableMap<String, Integer>(Ordering.natural());
map.put("a", 5);
map.put("b", 1);
map.put("c", 3);
assertEquals("b",map.firstKey());
assertEquals("a",map.lastKey());
map.put("d",0);
assertEquals("d",map.firstKey());
//ensure it's still a map (by overwriting a key, but with a new value)
map.put("d", 2);
assertEquals("b", map.firstKey());
//Ensure multiple values do not clobber keys
map.put("e", 2);
assertEquals(5, map.size());
assertEquals(2, (int) map.get("e"));
assertEquals(2, (int) map.get("d"));
}
}
When we put, we ensure that the hash map has the value for the comparator, and then put to the TreeSet for sorting. But before that we check the hash map to see that the key is not actually a duplicate. Also, the comparator that we create will also include the key so that duplicate values don't delete the non-duplicate keys (due to == comparison). These 2 items are vital for ensuring the map contract is kept; if you think you don't want that, then you're almost at the point of reversing the map entirely (to Map<V,K>
).
当我们放置时,我们确保哈希映射具有比较器的值,然后将其放到TreeSet中进行排序。但在此之前,我们要检查哈希映射,看看键是否实际上是复制的。另外,我们创建的comparator也会包含键,这样重复的值就不会删除非重复的键(由于==比较)。这两个项目对于确保地图合同的保存是至关重要的;如果你认为你不想要它,那么你几乎完全颠倒了地图(映射
The constructor would need to be called as
构造函数需要被调用。
new ValueComparableMap(Ordering.natural());
//or
new ValueComparableMap(Ordering.from(comparator));
#4
195
Java 8 offers a new answer: convert the entries into a stream, and use the comparator combinators from Map.Entry:
Java 8提供了一个新的答案:将条目转换成流,并使用来自Map.Entry的比较器组合器:
Stream<Map.Entry<K,V>> sorted =
map.entrySet().stream()
.sorted(Map.Entry.comparingByValue());
This will let you consume the entries sorted in ascending order of value. If you want descending value, simply reverse the comparator:
这将允许您按值的升序对条目进行排序。如果您想要下降的值,只需反转比较器:
Stream<Map.Entry<K,V>> sorted =
map.entrySet().stream()
.sorted(Collections.reverseOrder(Map.Entry.comparingByValue()));
If the values are not comparable, you can pass an explicit comparator:
如果值是不可比较的,您可以通过一个显式比较器:
Stream<Map.Entry<K,V>> sorted =
map.entrySet().stream()
.sorted(Map.Entry.comparingByValue(comparator));
You can then proceed to use other stream operations to consume the data. For example, if you want the top 10 in a new map:
然后,您可以继续使用其他流操作来使用数据。例如,如果你想要一张新地图的前10名:
Map<K,V> topTen =
map.entrySet().stream()
.sorted(Map.Entry.comparingByValue(Comparator.reverseOrder()))
.limit(10)
.collect(Collectors.toMap(
Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new));
Or print to System.out
:
或打印到system . out:
map.entrySet().stream()
.sorted(Map.Entry.comparingByValue())
.forEach(System.out::println);
#5
170
From http://www.programmersheaven.com/download/49349/download.aspx
从http://www.programmersheaven.com/download/49349/download.aspx
private static <K, V> Map<K, V> sortByValue(Map<K, V> map) {
List<Entry<K, V>> list = new LinkedList<>(map.entrySet());
Collections.sort(list, new Comparator<Object>() {
@SuppressWarnings("unchecked")
public int compare(Object o1, Object o2) {
return ((Comparable<V>) ((Map.Entry<K, V>) (o1)).getValue()).compareTo(((Map.Entry<K, V>) (o2)).getValue());
}
});
Map<K, V> result = new LinkedHashMap<>();
for (Iterator<Entry<K, V>> it = list.iterator(); it.hasNext();) {
Map.Entry<K, V> entry = (Map.Entry<K, V>) it.next();
result.put(entry.getKey(), entry.getValue());
}
return result;
}
#6
28
Sorting the keys requires the Comparator to look up each value for each comparison. A more scalable solution would use the entrySet directly, since then the value would be immediately available for each comparison (although I haven't backed this up by numbers).
对键进行排序需要比较器查找每个比较的每个值。一个更可扩展的解决方案将直接使用entrySet,从那时起,每个比较都可以立即使用该值(尽管我没有通过数字来支持它)。
Here's a generic version of such a thing:
这是这样一件事的通用版本:
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());
}
}
There are ways to lessen memory rotation for the above solution. The first ArrayList created could for instance be re-used as a return value; this would require suppression of some generics warnings, but it might be worth it for re-usable library code. Also, the Comparator does not have to be re-allocated at every invocation.
有一些方法可以减少上述解决方案的内存旋转。创建的第一个ArrayList可以被重新用作返回值;这需要对一些泛型警告进行抑制,但是对于可重用的库代码来说,这可能是值得的。而且,比较器不必在每次调用时重新分配。
Here's a more efficient albeit less appealing version:
这里有一个更有效但不那么吸引人的版本:
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();
Finally, if you need to continously access the sorted information (rather than just sorting it once in a while), you can use an additional multi map. Let me know if you need more details...
最后,如果您需要连续地访问已排序的信息(而不是仅在一段时间内对它进行排序),您可以使用一个额外的多映射。如果你需要更多的细节,请告诉我。
#7
27
With Java 8, you can use the streams api to do it in a significantly less verbose way:
使用Java 8,您可以使用streams api以更少的冗长的方式来完成它:
Map<K, V> sortedMap = map.entrySet().stream()
.sorted(Entry.comparingByValue())
.collect(toMap(Entry::getKey, Entry::getValue,
(e1,e2) -> e1, LinkedHashMap::new));
#8
25
The commons-collections library contains a solution called TreeBidiMap. Or, you could have a look at the Google Collections API. It has TreeMultimap which you could use.
common -collection库包含一个名为TreeBidiMap的解决方案。或者,您可以查看一下谷歌集合API。它有TreeMultimap,你可以使用它。
And if you don't want to use these framework... they come with source code.
如果你不想使用这些框架…他们有源代码。
#9
23
I've looked at the given answers, but a lot of them are more complicated than needed or remove map elements when several keys have same value.
我已经查看了给定的答案,但是其中很多都比需要的复杂,或者在几个键具有相同的值时移除映射元素。
Here is a solution that I think fits better:
这里有一个我认为更好的解决方案:
public static <K, V extends Comparable<V>> Map<K, V> sortByValues(final Map<K, V> map) {
Comparator<K> valueComparator = new Comparator<K>() {
public int compare(K k1, K k2) {
int compare = map.get(k2).compareTo(map.get(k1));
if (compare == 0) return 1;
else return compare;
}
};
Map<K, V> sortedByValues = new TreeMap<K, V>(valueComparator);
sortedByValues.putAll(map);
return sortedByValues;
}
Note that the map is sorted from the highest value to the lowest.
注意,地图是从最高的值到最低的。
#10
18
To accomplish this with the new features in Java 8:
用Java 8的新特性来实现这一点:
import static java.util.Map.Entry.comparingByValue;
import static java.util.stream.Collectors.toList;
<K, V> List<Entry<K, V>> sort(Map<K, V> map, Comparator<? super V> comparator) {
return map.entrySet().stream().sorted(comparingByValue(comparator)).collect(toList());
}
The entries are ordered by their values using the given comparator. Alternatively, if your values are mutually comparable, no explicit comparator is needed:
通过使用给定的比较器,这些条目被它们的值排序。或者,如果您的值是相比较的,则不需要显式比较器:
<K, V extends Comparable<? super V>> List<Entry<K, V>> sort(Map<K, V> map) {
return map.entrySet().stream().sorted(comparingByValue()).collect(toList());
}
The returned list is a snapshot of the given map at the time this method is called, so neither will reflect subsequent changes to the other. For a live iterable view of the map:
返回的列表是在调用此方法时的给定映射的快照,因此不会反映对另一个映射的后续更改。关于地图的实时迭代视图:
<K, V extends Comparable<? super V>> Iterable<Entry<K, V>> sort(Map<K, V> map) {
return () -> map.entrySet().stream().sorted(comparingByValue()).iterator();
}
The returned iterable creates a fresh snapshot of the given map each time it's iterated, so barring concurrent modification, it will always reflect the current state of the map.
返回的iterable在每次迭代时创建给定映射的一个新快照,因此除非进行并行修改,它将始终反映映射的当前状态。
#11
15
Create customized comparator and use it while creating new TreeMap object.
创建自定义的比较器,并在创建新的TreeMap对象时使用它。
class MyComparator implements Comparator<Object> {
Map<String, Integer> map;
public MyComparator(Map<String, Integer> map) {
this.map = map;
}
public int compare(Object o1, Object o2) {
if (map.get(o2) == map.get(o1))
return 1;
else
return ((Integer) map.get(o2)).compareTo((Integer)
map.get(o1));
}
}
Use the below code in your main func
在主函数中使用下面的代码。
Map<String, Integer> lMap = new HashMap<String, Integer>();
lMap.put("A", 35);
lMap.put("B", 75);
lMap.put("C", 50);
lMap.put("D", 50);
MyComparator comparator = new MyComparator(lMap);
Map<String, Integer> newMap = new TreeMap<String, Integer>(comparator);
newMap.putAll(lMap);
System.out.println(newMap);
Output:
输出:
{B=75, D=50, C=50, A=35}
#12
14
While I agree that the constant need to sort a map is probably a smell, I think the following code is the easiest way to do it without using a different data structure.
虽然我同意对地图进行排序可能是一种气味,但我认为以下代码是最简单的方法,无需使用不同的数据结构。
public class MapUtilities {
public static <K, V extends Comparable<V>> List<Entry<K, V>> sortByValue(Map<K, V> map) {
List<Entry<K, V>> entries = new ArrayList<Entry<K, V>>(map.entrySet());
Collections.sort(entries, new ByValue<K, V>());
return entries;
}
private static class ByValue<K, V extends Comparable<V>> implements Comparator<Entry<K, V>> {
public int compare(Entry<K, V> o1, Entry<K, V> o2) {
return o1.getValue().compareTo(o2.getValue());
}
}
}
}
And here is an embarrassingly incomplete unit test:
这是一个令人尴尬的不完整单元测试:
public class MapUtilitiesTest extends TestCase {
public void testSorting() {
HashMap<String, Integer> map = new HashMap<String, Integer>();
map.put("One", 1);
map.put("Two", 2);
map.put("Three", 3);
List<Map.Entry<String, Integer>> sorted = MapUtilities.sortByValue(map);
assertEquals("First", "One", sorted.get(0).getKey());
assertEquals("Second", "Two", sorted.get(1).getKey());
assertEquals("Third", "Three", sorted.get(2).getKey());
}
}
}
The result is a sorted list of Map.Entry objects, from which you can obtain the keys and values.
结果是一个有序的地图列表。输入对象,从中可以获得键和值。
#13
12
Use a generic comparator such as :
使用通用比较器,例如:
final class MapValueComparator<K,V extends Comparable<V>> implements Comparator<K> {
private Map<K,V> map;
private MapValueComparator() {
super();
}
public MapValueComparator(Map<K,V> map) {
this();
this.map = map;
}
public int compare(K o1, K o2) {
return map.get(o1).compareTo(map.get(o2));
}
}
#14
11
The answer voted for the most does not work when you have 2 items that equals. the TreeMap leaves equal values out.
当你有两个相等的项时,大多数的答案是无效的。TreeMap的值是相等的。
the exmaple: unsorted map
例子:未分类的地图
key/value: D/67.3 key/value: A/99.5 key/value: B/67.4 key/value: C/67.5 key/value: E/99.5
results
结果
key/value: A/99.5 key/value: C/67.5 key/value: B/67.4 key/value: D/67.3
So leaves out E!!
所以遗漏E ! !
For me it worked fine to adjust the comparator, if it equals do not return 0 but -1.
对我来说,调整比较器是可行的,如果它等于不返回0但是-1。
in the example:
在这个例子中:
class ValueComparator implements Comparator {
类ValueComparator实现Comparator {
Map base; public ValueComparator(Map base) { this.base = base; }
地图基础;public ValueComparator(Map base) {this。基础=基地;}
public int compare(Object a, Object b) {
public int compare(对象a,对象b) {
if((Double)base.get(a) < (Double)base.get(b)) { return 1; } else if((Double)base.get(a) == (Double)base.get(b)) { return -1; } else { return -1; }
} }
} }
now it returns:
现在它返回:
unsorted map:
未分类的地图:
key/value: D/67.3 key/value: A/99.5 key/value: B/67.4 key/value: C/67.5 key/value: E/99.5
results:
结果:
key/value: A/99.5 key/value: E/99.5 key/value: C/67.5 key/value: B/67.4 key/value: D/67.3
as a response to Aliens (2011 nov. 22): I Am using this solution for a map of Integer Id's and names, but the idea is the same, so might be the code above is not correct (I will write it in a test and give you the correct code), this is the code for a Map sorting, based on the solution above:
作为应对外星人(2011年11月22日):我使用这个解决方案的地图整数Id和名称,但这个想法是相同的,所以可能是上面的代码是不正确的(我把它写在一个测试,会给你正确的代码),这是一个地图的代码排序,基于上面的解决方案:
package nl.iamit.util;
import java.util.Comparator;
import java.util.Map;
public class Comparators {
public static class MapIntegerStringComparator implements Comparator {
Map<Integer, String> base;
public MapIntegerStringComparator(Map<Integer, String> base) {
this.base = base;
}
public int compare(Object a, Object b) {
int compare = ((String) base.get(a))
.compareTo((String) base.get(b));
if (compare == 0) {
return -1;
}
return compare;
}
}
}
and this is the test class (I just tested it, and this works for the Integer, String Map:
这是测试类(我刚刚测试过,这对于整数,字符串映射是这样的:
package test.nl.iamit.util;
import java.util.HashMap;
import java.util.TreeMap;
import nl.iamit.util.Comparators;
import org.junit.Test;
import static org.junit.Assert.assertArrayEquals;
public class TestComparators {
@Test
public void testMapIntegerStringComparator(){
HashMap<Integer, String> unSoretedMap = new HashMap<Integer, String>();
Comparators.MapIntegerStringComparator bvc = new Comparators.MapIntegerStringComparator(
unSoretedMap);
TreeMap<Integer, String> sorted_map = new TreeMap<Integer, String>(bvc);
//the testdata:
unSoretedMap.put(new Integer(1), "E");
unSoretedMap.put(new Integer(2), "A");
unSoretedMap.put(new Integer(3), "E");
unSoretedMap.put(new Integer(4), "B");
unSoretedMap.put(new Integer(5), "F");
sorted_map.putAll(unSoretedMap);
Object[] targetKeys={new Integer(2),new Integer(4),new Integer(3),new Integer(1),new Integer(5) };
Object[] currecntKeys=sorted_map.keySet().toArray();
assertArrayEquals(targetKeys,currecntKeys);
}
}
here is the code for the Comparator of a Map:
这是地图比较器的代码:
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;
}
}
}
and this is the testcase for this:
这是这个的测试案例:
@Test
public void testMapStringDoubleComparator(){
HashMap<String, Double> unSoretedMap = new HashMap<String, Double>();
Comparators.MapStringDoubleComparator bvc = new Comparators.MapStringDoubleComparator(
unSoretedMap);
TreeMap<String, Double> sorted_map = new TreeMap<String, Double>(bvc);
//the testdata:
unSoretedMap.put("D",new Double(67.3));
unSoretedMap.put("A",new Double(99.5));
unSoretedMap.put("B",new Double(67.4));
unSoretedMap.put("C",new Double(67.5));
unSoretedMap.put("E",new Double(99.5));
sorted_map.putAll(unSoretedMap);
Object[] targetKeys={"D","B","C","E","A"};
Object[] currecntKeys=sorted_map.keySet().toArray();
assertArrayEquals(targetKeys,currecntKeys);
}
of cource you can make this a lot more generic, but I just needed it for 1 case (the Map)
当然,你可以让它更通用一些,但是我只需要一个例子(地图)
#15
10
Instead of using Collections.sort
as some do I'd suggest using Arrays.sort
. Actually what Collections.sort
does is something like this:
而不是使用集合。就像我建议使用Arrays.sort那样。实际上集合。排序是这样的:
public static <T extends Comparable<? super T>> void sort(List<T> list) {
Object[] a = list.toArray();
Arrays.sort(a);
ListIterator<T> i = list.listIterator();
for (int j=0; j<a.length; j++) {
i.next();
i.set((T)a[j]);
}
}
It just calls toArray
on the list and then uses Arrays.sort
. This way all the map entries will be copied three times: once from the map to the temporary list (be it a LinkedList or ArrayList), then to the temporary array and finally to the new map.
它只调用列表中的toArray然后使用Arrays.sort。这样,所有的映射条目将被复制三次:一次从映射到临时列表(无论是LinkedList还是ArrayList),然后是临时数组,最后是新映射。
My solution ommits this one step as it does not create unnecessary LinkedList. Here is the code, generic-friendly and performance-optimal:
我的解决方案省略了这一步,因为它没有创建不必要的LinkedList。这里是代码,一般友好和性能最佳:
public static <K, V extends Comparable<? super V>> Map<K, V> sortByValue(Map<K, V> map)
{
@SuppressWarnings("unchecked")
Map.Entry<K,V>[] array = map.entrySet().toArray(new Map.Entry[map.size()]);
Arrays.sort(array, new Comparator<Map.Entry<K, V>>()
{
public int compare(Map.Entry<K, V> e1, Map.Entry<K, V> e2)
{
return e1.getValue().compareTo(e2.getValue());
}
});
Map<K, V> result = new LinkedHashMap<K, V>();
for (Map.Entry<K, V> entry : array)
result.put(entry.getKey(), entry.getValue());
return result;
}
#16
8
This is a variation of Anthony's answer, which doesn't work if there are duplicate values:
这是Anthony的答案的变体,如果有重复的值,它就不起作用了:
public static <K, V extends Comparable<V>> Map<K, V> sortMapByValues(final Map<K, V> map) {
Comparator<K> valueComparator = new Comparator<K>() {
public int compare(K k1, K k2) {
final V v1 = map.get(k1);
final V v2 = map.get(k2);
/* Not sure how to handle nulls ... */
if (v1 == null) {
return (v2 == null) ? 0 : 1;
}
int compare = v2.compareTo(v1);
if (compare != 0)
{
return compare;
}
else
{
Integer h1 = k1.hashCode();
Integer h2 = k2.hashCode();
return h2.compareTo(h1);
}
}
};
Map<K, V> sortedByValues = new TreeMap<K, V>(valueComparator);
sortedByValues.putAll(map);
return sortedByValues;
}
Note that it's rather up in the air how to handle nulls.
注意,在air中,如何处理nulls是相当困难的。
One important advantage of this approach is that it actually returns a Map, unlike some of the other solutions offered here.
这种方法的一个重要优点是,它实际上返回了一个映射,不像这里提供的其他解决方案。
#17
7
Major problem. If you use the first answer (Google takes you here), change the comparator to add an equal clause, otherwise you cannot get values from the sorted_map by keys:
主要的问题。如果您使用第一个答案(谷歌带您在这里),请更改comparator以添加一个相等的子句,否则您不能通过键获取sorted_map中的值:
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
}
#18
7
There are a lot of answers for this question already, but none provided me what I was looking for, a map implementation that returns keys and entries sorted by the associated value, and maintains this property as keys and values are modified in the map. Two other questions ask for this specifically.
对于这个问题已经有很多答案了,但是没有一个能提供我想要的,一个映射实现,返回键和按关联值排序的条目,并在映射中维护这个属性作为键和值。还有两个问题需要特别说明。
I cooked up a generic friendly example that solves this use case. This implementation does not honor all of the contracts of the Map interface, such as reflecting value changes and removals in the sets return from keySet() and entrySet() in the original object. I felt such a solution would be too large to include in a Stack Overflow answer. If I manage to create a more complete implementation, perhaps I will post it to Github and then to it link in an updated version of this answer.
我编写了一个通用的友好示例来解决这个用例。该实现不尊重映射接口的所有契约,例如在原始对象中从keySet()和entrySet()返回的集合中反映值更改和删除。我觉得这样的解决方案太大了,不能包含在堆栈溢出的答案中。如果我设法创建一个更完整的实现,也许我会将它发布到Github,然后再将其链接到这个答案的更新版本中。
import java.util.*;
/**
* A map where {@link #keySet()} and {@link #entrySet()} return sets ordered
* by associated values based on the the comparator provided at construction
* time. The order of two or more keys with identical values is not defined.
* <p>
* Several contracts of the Map interface are not satisfied by this minimal
* implementation.
*/
public class ValueSortedMap<K, V> extends HashMap<K, V> {
protected Map<V, Collection<K>> valueToKeysMap;
// uses natural order of value object, if any
public ValueSortedMap() {
this((Comparator<? super V>) null);
}
public ValueSortedMap(Comparator<? super V> valueComparator) {
this.valueToKeysMap = new TreeMap<V, Collection<K>>(valueComparator);
}
public boolean containsValue(Object o) {
return valueToKeysMap.containsKey(o);
}
public V put(K k, V v) {
V oldV = null;
if (containsKey(k)) {
oldV = get(k);
valueToKeysMap.get(oldV).remove(k);
}
super.put(k, v);
if (!valueToKeysMap.containsKey(v)) {
Collection<K> keys = new ArrayList<K>();
keys.add(k);
valueToKeysMap.put(v, keys);
} else {
valueToKeysMap.get(v).add(k);
}
return oldV;
}
public void putAll(Map<? extends K, ? extends V> m) {
for (Map.Entry<? extends K, ? extends V> e : m.entrySet())
put(e.getKey(), e.getValue());
}
public V remove(Object k) {
V oldV = null;
if (containsKey(k)) {
oldV = get(k);
super.remove(k);
valueToKeysMap.get(oldV).remove(k);
}
return oldV;
}
public void clear() {
super.clear();
valueToKeysMap.clear();
}
public Set<K> keySet() {
LinkedHashSet<K> ret = new LinkedHashSet<K>(size());
for (V v : valueToKeysMap.keySet()) {
Collection<K> keys = valueToKeysMap.get(v);
ret.addAll(keys);
}
return ret;
}
public Set<Map.Entry<K, V>> entrySet() {
LinkedHashSet<Map.Entry<K, V>> ret = new LinkedHashSet<Map.Entry<K, V>>(size());
for (Collection<K> keys : valueToKeysMap.values()) {
for (final K k : keys) {
final V v = get(k);
ret.add(new Map.Entry<K,V>() {
public K getKey() {
return k;
}
public V getValue() {
return v;
}
public V setValue(V v) {
throw new UnsupportedOperationException();
}
});
}
}
return ret;
}
}
#19
5
This is just too complicated. Maps were not supposed to do such job as sorting them by Value. The easiest way is to create your own Class so it fits your requirement.
这太复杂了。地图不应该是按价值分类的。最简单的方法是创建您自己的类,以满足您的需求。
In example lower you are supposed to add TreeMap a comparator at place where * is. But by java API it gives comparator only keys, not values. All of examples stated here is based on 2 Maps. One Hash and one new Tree. Which is odd.
例如,您应该在*所在的位置添加TreeMap比较器。但是通过java API,它只提供比较器键,而不是值。这里所述的所有示例都基于两个映射。一个哈希和一个新树。这是非常奇怪的。
The example:
示例:
Map<Driver driver, Float time> map = new TreeMap<Driver driver, Float time>(*);
So change the map into a set this way:
所以把地图改成这样:
ResultComparator rc = new ResultComparator();
Set<Results> set = new TreeSet<Results>(rc);
You will create class Results
,
您将创建类结果,
public class Results {
private Driver driver;
private Float time;
public Results(Driver driver, Float time) {
this.driver = driver;
this.time = time;
}
public Float getTime() {
return time;
}
public void setTime(Float time) {
this.time = time;
}
public Driver getDriver() {
return driver;
}
public void setDriver (Driver driver) {
this.driver = driver;
}
}
and the Comparator class:
和比较器类:
public class ResultsComparator implements Comparator<Results> {
public int compare(Results t, Results t1) {
if (t.getTime() < t1.getTime()) {
return 1;
} else if (t.getTime() == t1.getTime()) {
return 0;
} else {
return -1;
}
}
}
This way you can easily add more dependencies.
通过这种方式,您可以轻松地添加更多的依赖项。
And as the last point I'll add simple iterator:
作为最后一点,我将添加简单迭代器:
Iterator it = set.iterator();
while (it.hasNext()) {
Results r = (Results)it.next();
System.out.println( r.getDriver().toString
//or whatever that is related to Driver class -getName() getSurname()
+ " "
+ r.getTime()
);
}
#20
5
Best Approach
最好的方法
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.Set;
import java.util.Map.Entry;
public class OrderByValue {
public static void main(String a[]){
Map<String, Integer> map = new HashMap<String, Integer>();
map.put("java", 20);
map.put("C++", 45);
map.put("Unix", 67);
map.put("MAC", 26);
map.put("Why this kolavari", 93);
Set<Entry<String, Integer>> set = map.entrySet();
List<Entry<String, Integer>> list = new ArrayList<Entry<String, Integer>>(set);
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()).compareTo( o2.getValue() );//Ascending order
//return (o2.getValue()).compareTo( o1.getValue() );//Descending order
}
} );
for(Map.Entry<String, Integer> entry:list){
System.out.println(entry.getKey()+" ==== "+entry.getValue());
}
}}
Output
输出
java ==== 20
MAC ==== 26
C++ ==== 45
Unix ==== 67
Why this kolavari ==== 93
#21
4
Based on @devinmoore code, a map sorting methods using generics and supporting both ascending and descending ordering.
基于@devinmoore代码,一个使用泛型和支持升序和降序排序的地图排序方法。
/**
* Sort a map by it's keys in ascending order.
*
* @return new instance of {@link LinkedHashMap} contained sorted entries of supplied map.
* @author Maxim Veksler
*/
public static <K, V> LinkedHashMap<K, V> sortMapByKey(final Map<K, V> map) {
return sortMapByKey(map, SortingOrder.ASCENDING);
}
/**
* Sort a map by it's values in ascending order.
*
* @return new instance of {@link LinkedHashMap} contained sorted entries of supplied map.
* @author Maxim Veksler
*/
public static <K, V> LinkedHashMap<K, V> sortMapByValue(final Map<K, V> map) {
return sortMapByValue(map, SortingOrder.ASCENDING);
}
/**
* Sort a map by it's keys.
*
* @param sortingOrder {@link SortingOrder} enum specifying requested sorting order.
* @return new instance of {@link LinkedHashMap} contained sorted entries of supplied map.
* @author Maxim Veksler
*/
public static <K, V> LinkedHashMap<K, V> sortMapByKey(final Map<K, V> map, final SortingOrder sortingOrder) {
Comparator<Map.Entry<K, V>> comparator = new Comparator<Entry<K,V>>() {
public int compare(Entry<K, V> o1, Entry<K, V> o2) {
return comparableCompare(o1.getKey(), o2.getKey(), sortingOrder);
}
};
return sortMap(map, comparator);
}
/**
* Sort a map by it's values.
*
* @param sortingOrder {@link SortingOrder} enum specifying requested sorting order.
* @return new instance of {@link LinkedHashMap} contained sorted entries of supplied map.
* @author Maxim Veksler
*/
public static <K, V> LinkedHashMap<K, V> sortMapByValue(final Map<K, V> map, final SortingOrder sortingOrder) {
Comparator<Map.Entry<K, V>> comparator = new Comparator<Entry<K,V>>() {
public int compare(Entry<K, V> o1, Entry<K, V> o2) {
return comparableCompare(o1.getValue(), o2.getValue(), sortingOrder);
}
};
return sortMap(map, comparator);
}
@SuppressWarnings("unchecked")
private static <T> int comparableCompare(T o1, T o2, SortingOrder sortingOrder) {
int compare = ((Comparable<T>)o1).compareTo(o2);
switch (sortingOrder) {
case ASCENDING:
return compare;
case DESCENDING:
return (-1) * compare;
}
return 0;
}
/**
* Sort a map by supplied comparator logic.
*
* @return new instance of {@link LinkedHashMap} contained sorted entries of supplied map.
* @author Maxim Veksler
*/
public static <K, V> LinkedHashMap<K, V> sortMap(final Map<K, V> map, final Comparator<Map.Entry<K, V>> comparator) {
// Convert the map into a list of key,value pairs.
List<Map.Entry<K, V>> mapEntries = new LinkedList<Map.Entry<K, V>>(map.entrySet());
// Sort the converted list according to supplied comparator.
Collections.sort(mapEntries, comparator);
// Build a new ordered map, containing the same entries as the old map.
LinkedHashMap<K, V> result = new LinkedHashMap<K, V>(map.size() + (map.size() / 20));
for(Map.Entry<K, V> entry : mapEntries) {
// We iterate on the mapEntries list which is sorted by the comparator putting new entries into
// the targeted result which is a sorted map.
result.put(entry.getKey(), entry.getValue());
}
return result;
}
/**
* Sorting order enum, specifying request result sort behavior.
* @author Maxim Veksler
*
*/
public static enum SortingOrder {
/**
* Resulting sort will be from smaller to biggest.
*/
ASCENDING,
/**
* Resulting sort will be from biggest to smallest.
*/
DESCENDING
}
#22
4
Here is an OO solution (i.e., doesn't use static
methods):
这里有一个OO解决方案(即:,不使用静态方法):
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
public class SortableValueMap<K, V extends Comparable<V>>
extends LinkedHashMap<K, V> {
public SortableValueMap() { }
public SortableValueMap( Map<K, V> map ) {
super( map );
}
public void sortByValue() {
List<Map.Entry<K, V>> list = new LinkedList<Map.Entry<K, V>>( entrySet() );
Collections.sort( list, new Comparator<Map.Entry<K, V>>() {
public int compare( Map.Entry<K, V> entry1, Map.Entry<K, V> entry2 ) {
return entry1.getValue().compareTo( entry2.getValue() );
}
});
clear();
for( Map.Entry<K, V> entry : list ) {
put( entry.getKey(), entry.getValue() );
}
}
private static void print( String text, Map<String, Double> map ) {
System.out.println( text );
for( String key : map.keySet() ) {
System.out.println( "key/value: " + key + "/" + map.get( key ) );
}
}
public static void main( String[] args ) {
SortableValueMap<String, Double> map =
new SortableValueMap<String, Double>();
map.put( "A", 67.5 );
map.put( "B", 99.5 );
map.put( "C", 82.4 );
map.put( "D", 42.0 );
print( "Unsorted map", map );
map.sortByValue();
print( "Sorted map", map );
}
}
Hereby donated to the public domain.
特此捐赠给公共领域。
#23
4
Afaik the most cleaner way is utilizing collections to sort map on value:
Afaik最清洁的方法是利用集合来分类地图的价值:
Map<String, Long> map = new HashMap<String, Long>();
// populate with data to sort on Value
// use datastructure designed for sorting
Queue queue = new PriorityQueue( map.size(), new MapComparable() );
queue.addAll( map.entrySet() );
// get a sorted map
LinkedHashMap<String, Long> linkedMap = new LinkedHashMap<String, Long>();
for (Map.Entry<String, Long> entry; (entry = queue.poll())!=null;) {
linkedMap.put(entry.getKey(), entry.getValue());
}
public static class MapComparable implements Comparator<Map.Entry<String, Long>>{
public int compare(Entry<String, Long> e1, Entry<String, Long> e2) {
return e1.getValue().compareTo(e2.getValue());
}
}
#24
4
Since TreeMap<> does not work for values that can be equal, I used this:
因为TreeMap<>不适用于可以相等的值,所以我使用了这个:
private <K, V extends Comparable<? super V>> List<Entry<K, V>> sort(Map<K, V> map) {
List<Map.Entry<K, V>> list = new LinkedList<Map.Entry<K, V>>(map.entrySet());
Collections.sort(list, new Comparator<Map.Entry<K, V>>() {
public int compare(Map.Entry<K, V> o1, Map.Entry<K, V> o2) {
return o1.getValue().compareTo(o2.getValue());
}
});
return list;
}
You might want to put list in a LinkedHashMap, but if you're only going to iterate over it right away, that's superfluous...
你可能想把列表放在LinkedHashMap中,但是如果你只打算在上面迭代,那是多余的…
#25
4
Some simple changes in order to have a sorted map with pairs that have duplicate values. In the compare method (class ValueComparator) when values are equal do not return 0 but return the result of comparing the 2 keys. Keys are distinct in a map so you succeed to keep duplicate values (which are sorted by keys by the way). So the above example could be modified like this:
一些简单的更改,以便使用具有重复值的对进行排序映射。在比较方法(class ValueComparator)中,当值相等时,不返回0,但返回比较两个键的结果。键在映射中是不同的,所以您成功地保留了重复的值(顺便说一下,这些值是按键排序的)。上面的例子可以这样修改:
public int compare(Object a, Object b) {
if((Double)base.get(a) < (Double)base.get(b)) {
return 1;
} else if((Double)base.get(a) == (Double)base.get(b)) {
return ((String)a).compareTo((String)b);
} else {
return -1;
}
}
}
#26
4
For sure the solution of Stephen is really great, but for those who can't use Guava:
当然,斯蒂芬的解决方案真的很棒,但是对于那些不能使用番石榴的人来说:
Here's my solution for sorting by value a map. This solution handle the case where there are twice the same value etc...
这是我的解决方案,对地图进行排序。这个解决方案处理的情况是相同值的两倍。
// If you want to sort a map by value, and if there can be twice the same value:
// here is your original map
Map<String,Integer> mapToSortByValue = new HashMap<String, Integer>();
mapToSortByValue.put("A", 3);
mapToSortByValue.put("B", 1);
mapToSortByValue.put("C", 3);
mapToSortByValue.put("D", 5);
mapToSortByValue.put("E", -1);
mapToSortByValue.put("F", 1000);
mapToSortByValue.put("G", 79);
mapToSortByValue.put("H", 15);
// Sort all the map entries by value
Set<Map.Entry<String,Integer>> set = new TreeSet<Map.Entry<String,Integer>>(
new Comparator<Map.Entry<String,Integer>>(){
@Override
public int compare(Map.Entry<String,Integer> obj1, Map.Entry<String,Integer> obj2) {
Integer val1 = obj1.getValue();
Integer val2 = obj2.getValue();
// DUPLICATE VALUE CASE
// If the values are equals, we can't return 0 because the 2 entries would be considered
// as equals and one of them would be deleted (because we use a set, no duplicate, remember!)
int compareValues = val1.compareTo(val2);
if ( compareValues == 0 ) {
String key1 = obj1.getKey();
String key2 = obj2.getKey();
int compareKeys = key1.compareTo(key2);
if ( compareKeys == 0 ) {
// what you return here will tell us if you keep REAL KEY-VALUE duplicates in your set
// if you want to, do whatever you want but do not return 0 (but don't break the comparator contract!)
return 0;
}
return compareKeys;
}
return compareValues;
}
}
);
set.addAll(mapToSortByValue.entrySet());
// OK NOW OUR SET IS SORTED COOL!!!!
// And there's nothing more to do: the entries are sorted by value!
for ( Map.Entry<String,Integer> entry : set ) {
System.out.println("Set entries: " + entry.getKey() + " -> " + entry.getValue());
}
// But if you add them to an hashmap
Map<String,Integer> myMap = new HashMap<String,Integer>();
// When iterating over the set the order is still good in the println...
for ( Map.Entry<String,Integer> entry : set ) {
System.out.println("Added to result map entries: " + entry.getKey() + " " + entry.getValue());
myMap.put(entry.getKey(), entry.getValue());
}
// But once they are in the hashmap, the order is not kept!
for ( Integer value : myMap.values() ) {
System.out.println("Result map values: " + value);
}
// Also this way doesn't work:
// Logic because the entryset is a hashset for hashmaps and not a treeset
// (and even if it was a treeset, it would be on the keys only)
for ( Map.Entry<String,Integer> entry : myMap.entrySet() ) {
System.out.println("Result map entries: " + entry.getKey() + " -> " + entry.getValue());
}
// CONCLUSION:
// If you want to iterate on a map ordered by value, you need to remember:
// 1) Maps are only sorted by keys, so you can't sort them directly by value
// 2) So you simply CAN'T return a map to a sortMapByValue function
// 3) You can't reverse the keys and the values because you have duplicate values
// This also means you can't neither use Guava/Commons bidirectionnal treemaps or stuff like that
// SOLUTIONS
// So you can:
// 1) only sort the values which is easy, but you loose the key/value link (since you have duplicate values)
// 2) sort the map entries, but don't forget to handle the duplicate value case (like i did)
// 3) if you really need to return a map, use a LinkedHashMap which keep the insertion order
The exec: http://www.ideone.com/dq3Lu
exec:http://www.ideone.com/dq3Lu
The output:
输出:
Set entries: E -> -1
Set entries: B -> 1
Set entries: A -> 3
Set entries: C -> 3
Set entries: D -> 5
Set entries: H -> 15
Set entries: G -> 79
Set entries: F -> 1000
Added to result map entries: E -1
Added to result map entries: B 1
Added to result map entries: A 3
Added to result map entries: C 3
Added to result map entries: D 5
Added to result map entries: H 15
Added to result map entries: G 79
Added to result map entries: F 1000
Result map values: 5
Result map values: -1
Result map values: 1000
Result map values: 79
Result map values: 3
Result map values: 1
Result map values: 3
Result map values: 15
Result map entries: D -> 5
Result map entries: E -> -1
Result map entries: F -> 1000
Result map entries: G -> 79
Result map entries: A -> 3
Result map entries: B -> 1
Result map entries: C -> 3
Result map entries: H -> 15
Hope it will help some folks
希望它能帮助一些人。
#27
4
I've merged the solutions of user157196 and Carter Page:
我已经合并了user157196和Carter Page的解决方案:
class MapUtil {
public static <K, V extends Comparable<? super V>> Map<K, V> sortByValue( Map<K, V> map ){
ValueComparator<K,V> bvc = new ValueComparator<K,V>(map);
TreeMap<K,V> sorted_map = new TreeMap<K,V>(bvc);
sorted_map.putAll(map);
return sorted_map;
}
}
class ValueComparator<K, V extends Comparable<? super V>> implements Comparator<K> {
Map<K, V> base;
public ValueComparator(Map<K, V> base) {
this.base = base;
}
public int compare(K a, K b) {
int result = (base.get(a).compareTo(base.get(b)));
if (result == 0) result=1;
// returning 0 would merge keys
return result;
}
}
#28
3
Depending on the context, using java.util.LinkedHashMap<T>
which rememebers the order in which items are placed into the map. Otherwise, if you need to sort values based on their natural ordering, I would recommend maintaining a separate List which can be sorted via Collections.sort()
.
取决于上下文,使用java.util。LinkedHashMap
#29
3
If you have duplicate keys and only a small set of data (<1000) and your code is not performance critical you can just do the following:
如果您有重复的密钥,并且只有一小部分数据(<1000),并且您的代码不是性能关键的,您可以执行以下操作:
Map<String,Integer> tempMap=new HashMap<String,Integer>(inputUnsortedMap);
LinkedHashMap<String,Integer> sortedOutputMap=new LinkedHashMap<String,Integer>();
for(int i=0;i<inputUnsortedMap.size();i++){
Map.Entry<String,Integer> maxEntry=null;
Integer maxValue=-1;
for(Map.Entry<String,Integer> entry:tempMap.entrySet()){
if(entry.getValue()>maxValue){
maxValue=entry.getValue();
maxEntry=entry;
}
}
tempMap.remove(maxEntry.getKey());
sortedOutputMap.put(maxEntry.getKey(),maxEntry.getValue());
}
inputUnsortedMap is the input to the code.
inputUnsortedMap是代码的输入。
The variable sortedOutputMap will contain the data in decending order when iterated over. To change order just change > to a < in the if statement.
变量sortedOutputMap将在迭代结束时包含decending order中的数据。若要更改顺序,只需将>更改为if语句中的一个<。
Is not the fastest sort but does the job without any additional dependencies.
并不是最快的排序,但是没有任何附加的依赖项。
#30
3
You can try Guava's multimaps:
你可以试试番石榴的multimaps:
TreeMap<Integer, Collection<String>> sortedMap = new TreeMap<>(
Multimaps.invertFrom(Multimaps.forMap(originalMap),
ArrayListMultimap.<Integer, String>create()).asMap());
As a result you get a map from original values to collections of keys that correspond to them. This approach can be used even if there are multiple keys for the same value.
因此,您可以从原始值到对应于它们的键集合得到一个映射。即使有相同值的多个键,也可以使用此方法。
#1
746
Here's a generic-friendly version:
这里有一个generic-friendly版本:
public class MapUtil {
public static <K, V extends Comparable<? super V>> Map<K, V> sortByValue(Map<K, V> map) {
List<Entry<K, V>> list = new ArrayList<>(map.entrySet());
list.sort(Entry.comparingByValue());
Map<K, V> result = new LinkedHashMap<>();
for (Entry<K, V> entry : list) {
result.put(entry.getKey(), entry.getValue());
}
return result;
}
}
#2
400
Important note:
This code can break in multiple ways. If you intend to use the code provided, be sure to read the comments as well to be aware of the implications. For example, values can no longer be retrieved by their key. (get
always returns null
.)
此代码可以以多种方式中断。如果您打算使用所提供的代码,请务必阅读注释并了解其含义。例如,值不能再由其键检索。(总是返回null。)
It seems much easier than all of the foregoing. Use a TreeMap as follows:
这似乎比前面所有的都容易。使用TreeMap如下:
public class Testing {
public static void main(String[] args) {
HashMap<String, Double> map = new HashMap<String, Double>();
ValueComparator bvc = new ValueComparator(map);
TreeMap<String, Double> sorted_map = new TreeMap<String, Double>(bvc);
map.put("A", 99.5);
map.put("B", 67.4);
map.put("C", 67.4);
map.put("D", 67.3);
System.out.println("unsorted map: " + map);
sorted_map.putAll(map);
System.out.println("results: " + sorted_map);
}
}
class ValueComparator implements Comparator<String> {
Map<String, Double> base;
public ValueComparator(Map<String, Double> base) {
this.base = base;
}
// Note: this comparator imposes orderings that are inconsistent with
// equals.
public int compare(String a, String b) {
if (base.get(a) >= base.get(b)) {
return -1;
} else {
return 1;
} // returning 0 would merge keys
}
}
Output:
输出:
unsorted map: {D=67.3, A=99.5, B=67.4, C=67.4}
results: {D=67.3, B=67.4, C=67.4, A=99.5}
#3
206
Three 1-line answers...
三种1条线的答案……
I would use Google Collections Guava to do this - if your values are Comparable
then you can use
我将使用谷歌集合Guava来做这个——如果你的值是可比较的,那么你可以使用。
valueComparator = Ordering.natural().onResultOf(Functions.forMap(map))
Which will create a function (object) for the map [that takes any of the keys as input, returning the respective value], and then apply natural (comparable) ordering to them [the values].
它将为映射创建一个函数(对象),它将任何键作为输入,返回相应的值),然后将自然(可比较的)排序应用到它们(值)。
If they're not comparable, then you'll need to do something along the lines of
如果它们不具有可比性,那么你就需要沿着这条线做一些事情。
valueComparator = Ordering.from(comparator).onResultOf(Functions.forMap(map))
These may be applied to a TreeMap (as Ordering
extends Comparator
), or a LinkedHashMap after some sorting
这些可以应用于TreeMap(如订购扩展比较器),或在一些排序之后的LinkedHashMap。
NB: If you are going to use a TreeMap, remember that if a comparison == 0, then the item is already in the list (which will happen if you have multiple values that compare the same). To alleviate this, you could add your key to the comparator like so (presuming that your keys and values are Comparable
):
NB:如果您打算使用TreeMap,请记住,如果比较== 0,那么该项就已经在列表中(如果您有多个比较相同的值,则会发生这种情况)。为了缓解这种情况,您可以将您的密钥添加到comparator(假定您的键和值是可比较的):
valueComparator = Ordering.natural().onResultOf(Functions.forMap(map)).compound(Ordering.natural())
= Apply natural ordering to the value mapped by the key, and compound that with the natural ordering of the key
=将自然排序应用于键映射的值,并将其与键的自然排序结合起来。
Note that this will still not work if your keys compare to 0, but this should be sufficient for most comparable
items (as hashCode
, equals
and compareTo
are often in sync...)
请注意,如果您的键与0比较,这仍然是无效的,但是对于大多数可比较的项来说,这应该足够了(因为hashCode、equals和compareTo通常是同步的…)
See Ordering.onResultOf() and Functions.forMap().
看到Ordering.onResultOf()和Functions.forMap()。
Implementation
So now that we've got a comparator that does what we want, we need to get a result from it.
现在我们有了一个比较器它可以做我们想要的,我们需要得到它的结果。
map = ImmutableSortedMap.copyOf(myOriginalMap, valueComparator);
Now this will most likely work work, but:
现在这很可能是工作,但是:
- needs to be done given a complete finished map
- 需要完成一张完整的地图。
- Don't try the comparators above on a
TreeMap
; there's no point trying to compare an inserted key when it doesn't have a value until after the put, i.e., it will break really fast - 不要在TreeMap上尝试以上的比较器;当插入键没有值的时候,尝试比较插入的键是没有意义的,比如。它会很快断裂。
Point 1 is a bit of a deal-breaker for me; google collections is incredibly lazy (which is good: you can do pretty much every operation in an instant; the real work is done when you start using the result), and this requires copying a whole map!
第一点对我来说是一种破坏;谷歌集合非常懒惰(这很好:你可以在瞬间完成几乎所有的操作;真正的工作是在您开始使用结果时完成的),而这需要复制整个映射!
"Full" answer/Live sorted map by values
Don't worry though; if you were obsessed enough with having a "live" map sorted in this manner, you could solve not one but both(!) of the above issues with something crazy like the following:
不要担心;如果你对“活的”地图有足够的兴趣,你可以用以下的疯狂的方式来解决上述问题:
Note: This has changed significantly in June 2012 - the previous code could never work: an internal HashMap is required to lookup the values without creating an infinite loop between the TreeMap.get()
-> compare()
and compare()
-> get()
注意:这在2012年6月发生了显著的变化——以前的代码无法工作:需要一个内部HashMap来查找值,而无需在TreeMap.get()中创建一个无限循环。
import static org.junit.Assert.assertEquals;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
import com.google.common.base.Functions;
import com.google.common.collect.Ordering;
class ValueComparableMap<K extends Comparable<K>,V> extends TreeMap<K,V> {
//A map for doing lookups on the keys for comparison so we don't get infinite loops
private final Map<K, V> valueMap;
ValueComparableMap(final Ordering<? super V> partialValueOrdering) {
this(partialValueOrdering, new HashMap<K,V>());
}
private ValueComparableMap(Ordering<? super V> partialValueOrdering,
HashMap<K, V> valueMap) {
super(partialValueOrdering //Apply the value ordering
.onResultOf(Functions.forMap(valueMap)) //On the result of getting the value for the key from the map
.compound(Ordering.natural())); //as well as ensuring that the keys don't get clobbered
this.valueMap = valueMap;
}
public V put(K k, V v) {
if (valueMap.containsKey(k)){
//remove the key in the sorted set before adding the key again
remove(k);
}
valueMap.put(k,v); //To get "real" unsorted values for the comparator
return super.put(k, v); //Put it in value order
}
public static void main(String[] args){
TreeMap<String, Integer> map = new ValueComparableMap<String, Integer>(Ordering.natural());
map.put("a", 5);
map.put("b", 1);
map.put("c", 3);
assertEquals("b",map.firstKey());
assertEquals("a",map.lastKey());
map.put("d",0);
assertEquals("d",map.firstKey());
//ensure it's still a map (by overwriting a key, but with a new value)
map.put("d", 2);
assertEquals("b", map.firstKey());
//Ensure multiple values do not clobber keys
map.put("e", 2);
assertEquals(5, map.size());
assertEquals(2, (int) map.get("e"));
assertEquals(2, (int) map.get("d"));
}
}
When we put, we ensure that the hash map has the value for the comparator, and then put to the TreeSet for sorting. But before that we check the hash map to see that the key is not actually a duplicate. Also, the comparator that we create will also include the key so that duplicate values don't delete the non-duplicate keys (due to == comparison). These 2 items are vital for ensuring the map contract is kept; if you think you don't want that, then you're almost at the point of reversing the map entirely (to Map<V,K>
).
当我们放置时,我们确保哈希映射具有比较器的值,然后将其放到TreeSet中进行排序。但在此之前,我们要检查哈希映射,看看键是否实际上是复制的。另外,我们创建的comparator也会包含键,这样重复的值就不会删除非重复的键(由于==比较)。这两个项目对于确保地图合同的保存是至关重要的;如果你认为你不想要它,那么你几乎完全颠倒了地图(映射
The constructor would need to be called as
构造函数需要被调用。
new ValueComparableMap(Ordering.natural());
//or
new ValueComparableMap(Ordering.from(comparator));
#4
195
Java 8 offers a new answer: convert the entries into a stream, and use the comparator combinators from Map.Entry:
Java 8提供了一个新的答案:将条目转换成流,并使用来自Map.Entry的比较器组合器:
Stream<Map.Entry<K,V>> sorted =
map.entrySet().stream()
.sorted(Map.Entry.comparingByValue());
This will let you consume the entries sorted in ascending order of value. If you want descending value, simply reverse the comparator:
这将允许您按值的升序对条目进行排序。如果您想要下降的值,只需反转比较器:
Stream<Map.Entry<K,V>> sorted =
map.entrySet().stream()
.sorted(Collections.reverseOrder(Map.Entry.comparingByValue()));
If the values are not comparable, you can pass an explicit comparator:
如果值是不可比较的,您可以通过一个显式比较器:
Stream<Map.Entry<K,V>> sorted =
map.entrySet().stream()
.sorted(Map.Entry.comparingByValue(comparator));
You can then proceed to use other stream operations to consume the data. For example, if you want the top 10 in a new map:
然后,您可以继续使用其他流操作来使用数据。例如,如果你想要一张新地图的前10名:
Map<K,V> topTen =
map.entrySet().stream()
.sorted(Map.Entry.comparingByValue(Comparator.reverseOrder()))
.limit(10)
.collect(Collectors.toMap(
Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new));
Or print to System.out
:
或打印到system . out:
map.entrySet().stream()
.sorted(Map.Entry.comparingByValue())
.forEach(System.out::println);
#5
170
From http://www.programmersheaven.com/download/49349/download.aspx
从http://www.programmersheaven.com/download/49349/download.aspx
private static <K, V> Map<K, V> sortByValue(Map<K, V> map) {
List<Entry<K, V>> list = new LinkedList<>(map.entrySet());
Collections.sort(list, new Comparator<Object>() {
@SuppressWarnings("unchecked")
public int compare(Object o1, Object o2) {
return ((Comparable<V>) ((Map.Entry<K, V>) (o1)).getValue()).compareTo(((Map.Entry<K, V>) (o2)).getValue());
}
});
Map<K, V> result = new LinkedHashMap<>();
for (Iterator<Entry<K, V>> it = list.iterator(); it.hasNext();) {
Map.Entry<K, V> entry = (Map.Entry<K, V>) it.next();
result.put(entry.getKey(), entry.getValue());
}
return result;
}
#6
28
Sorting the keys requires the Comparator to look up each value for each comparison. A more scalable solution would use the entrySet directly, since then the value would be immediately available for each comparison (although I haven't backed this up by numbers).
对键进行排序需要比较器查找每个比较的每个值。一个更可扩展的解决方案将直接使用entrySet,从那时起,每个比较都可以立即使用该值(尽管我没有通过数字来支持它)。
Here's a generic version of such a thing:
这是这样一件事的通用版本:
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());
}
}
There are ways to lessen memory rotation for the above solution. The first ArrayList created could for instance be re-used as a return value; this would require suppression of some generics warnings, but it might be worth it for re-usable library code. Also, the Comparator does not have to be re-allocated at every invocation.
有一些方法可以减少上述解决方案的内存旋转。创建的第一个ArrayList可以被重新用作返回值;这需要对一些泛型警告进行抑制,但是对于可重用的库代码来说,这可能是值得的。而且,比较器不必在每次调用时重新分配。
Here's a more efficient albeit less appealing version:
这里有一个更有效但不那么吸引人的版本:
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();
Finally, if you need to continously access the sorted information (rather than just sorting it once in a while), you can use an additional multi map. Let me know if you need more details...
最后,如果您需要连续地访问已排序的信息(而不是仅在一段时间内对它进行排序),您可以使用一个额外的多映射。如果你需要更多的细节,请告诉我。
#7
27
With Java 8, you can use the streams api to do it in a significantly less verbose way:
使用Java 8,您可以使用streams api以更少的冗长的方式来完成它:
Map<K, V> sortedMap = map.entrySet().stream()
.sorted(Entry.comparingByValue())
.collect(toMap(Entry::getKey, Entry::getValue,
(e1,e2) -> e1, LinkedHashMap::new));
#8
25
The commons-collections library contains a solution called TreeBidiMap. Or, you could have a look at the Google Collections API. It has TreeMultimap which you could use.
common -collection库包含一个名为TreeBidiMap的解决方案。或者,您可以查看一下谷歌集合API。它有TreeMultimap,你可以使用它。
And if you don't want to use these framework... they come with source code.
如果你不想使用这些框架…他们有源代码。
#9
23
I've looked at the given answers, but a lot of them are more complicated than needed or remove map elements when several keys have same value.
我已经查看了给定的答案,但是其中很多都比需要的复杂,或者在几个键具有相同的值时移除映射元素。
Here is a solution that I think fits better:
这里有一个我认为更好的解决方案:
public static <K, V extends Comparable<V>> Map<K, V> sortByValues(final Map<K, V> map) {
Comparator<K> valueComparator = new Comparator<K>() {
public int compare(K k1, K k2) {
int compare = map.get(k2).compareTo(map.get(k1));
if (compare == 0) return 1;
else return compare;
}
};
Map<K, V> sortedByValues = new TreeMap<K, V>(valueComparator);
sortedByValues.putAll(map);
return sortedByValues;
}
Note that the map is sorted from the highest value to the lowest.
注意,地图是从最高的值到最低的。
#10
18
To accomplish this with the new features in Java 8:
用Java 8的新特性来实现这一点:
import static java.util.Map.Entry.comparingByValue;
import static java.util.stream.Collectors.toList;
<K, V> List<Entry<K, V>> sort(Map<K, V> map, Comparator<? super V> comparator) {
return map.entrySet().stream().sorted(comparingByValue(comparator)).collect(toList());
}
The entries are ordered by their values using the given comparator. Alternatively, if your values are mutually comparable, no explicit comparator is needed:
通过使用给定的比较器,这些条目被它们的值排序。或者,如果您的值是相比较的,则不需要显式比较器:
<K, V extends Comparable<? super V>> List<Entry<K, V>> sort(Map<K, V> map) {
return map.entrySet().stream().sorted(comparingByValue()).collect(toList());
}
The returned list is a snapshot of the given map at the time this method is called, so neither will reflect subsequent changes to the other. For a live iterable view of the map:
返回的列表是在调用此方法时的给定映射的快照,因此不会反映对另一个映射的后续更改。关于地图的实时迭代视图:
<K, V extends Comparable<? super V>> Iterable<Entry<K, V>> sort(Map<K, V> map) {
return () -> map.entrySet().stream().sorted(comparingByValue()).iterator();
}
The returned iterable creates a fresh snapshot of the given map each time it's iterated, so barring concurrent modification, it will always reflect the current state of the map.
返回的iterable在每次迭代时创建给定映射的一个新快照,因此除非进行并行修改,它将始终反映映射的当前状态。
#11
15
Create customized comparator and use it while creating new TreeMap object.
创建自定义的比较器,并在创建新的TreeMap对象时使用它。
class MyComparator implements Comparator<Object> {
Map<String, Integer> map;
public MyComparator(Map<String, Integer> map) {
this.map = map;
}
public int compare(Object o1, Object o2) {
if (map.get(o2) == map.get(o1))
return 1;
else
return ((Integer) map.get(o2)).compareTo((Integer)
map.get(o1));
}
}
Use the below code in your main func
在主函数中使用下面的代码。
Map<String, Integer> lMap = new HashMap<String, Integer>();
lMap.put("A", 35);
lMap.put("B", 75);
lMap.put("C", 50);
lMap.put("D", 50);
MyComparator comparator = new MyComparator(lMap);
Map<String, Integer> newMap = new TreeMap<String, Integer>(comparator);
newMap.putAll(lMap);
System.out.println(newMap);
Output:
输出:
{B=75, D=50, C=50, A=35}
#12
14
While I agree that the constant need to sort a map is probably a smell, I think the following code is the easiest way to do it without using a different data structure.
虽然我同意对地图进行排序可能是一种气味,但我认为以下代码是最简单的方法,无需使用不同的数据结构。
public class MapUtilities {
public static <K, V extends Comparable<V>> List<Entry<K, V>> sortByValue(Map<K, V> map) {
List<Entry<K, V>> entries = new ArrayList<Entry<K, V>>(map.entrySet());
Collections.sort(entries, new ByValue<K, V>());
return entries;
}
private static class ByValue<K, V extends Comparable<V>> implements Comparator<Entry<K, V>> {
public int compare(Entry<K, V> o1, Entry<K, V> o2) {
return o1.getValue().compareTo(o2.getValue());
}
}
}
}
And here is an embarrassingly incomplete unit test:
这是一个令人尴尬的不完整单元测试:
public class MapUtilitiesTest extends TestCase {
public void testSorting() {
HashMap<String, Integer> map = new HashMap<String, Integer>();
map.put("One", 1);
map.put("Two", 2);
map.put("Three", 3);
List<Map.Entry<String, Integer>> sorted = MapUtilities.sortByValue(map);
assertEquals("First", "One", sorted.get(0).getKey());
assertEquals("Second", "Two", sorted.get(1).getKey());
assertEquals("Third", "Three", sorted.get(2).getKey());
}
}
}
The result is a sorted list of Map.Entry objects, from which you can obtain the keys and values.
结果是一个有序的地图列表。输入对象,从中可以获得键和值。
#13
12
Use a generic comparator such as :
使用通用比较器,例如:
final class MapValueComparator<K,V extends Comparable<V>> implements Comparator<K> {
private Map<K,V> map;
private MapValueComparator() {
super();
}
public MapValueComparator(Map<K,V> map) {
this();
this.map = map;
}
public int compare(K o1, K o2) {
return map.get(o1).compareTo(map.get(o2));
}
}
#14
11
The answer voted for the most does not work when you have 2 items that equals. the TreeMap leaves equal values out.
当你有两个相等的项时,大多数的答案是无效的。TreeMap的值是相等的。
the exmaple: unsorted map
例子:未分类的地图
key/value: D/67.3 key/value: A/99.5 key/value: B/67.4 key/value: C/67.5 key/value: E/99.5
results
结果
key/value: A/99.5 key/value: C/67.5 key/value: B/67.4 key/value: D/67.3
So leaves out E!!
所以遗漏E ! !
For me it worked fine to adjust the comparator, if it equals do not return 0 but -1.
对我来说,调整比较器是可行的,如果它等于不返回0但是-1。
in the example:
在这个例子中:
class ValueComparator implements Comparator {
类ValueComparator实现Comparator {
Map base; public ValueComparator(Map base) { this.base = base; }
地图基础;public ValueComparator(Map base) {this。基础=基地;}
public int compare(Object a, Object b) {
public int compare(对象a,对象b) {
if((Double)base.get(a) < (Double)base.get(b)) { return 1; } else if((Double)base.get(a) == (Double)base.get(b)) { return -1; } else { return -1; }
} }
} }
now it returns:
现在它返回:
unsorted map:
未分类的地图:
key/value: D/67.3 key/value: A/99.5 key/value: B/67.4 key/value: C/67.5 key/value: E/99.5
results:
结果:
key/value: A/99.5 key/value: E/99.5 key/value: C/67.5 key/value: B/67.4 key/value: D/67.3
as a response to Aliens (2011 nov. 22): I Am using this solution for a map of Integer Id's and names, but the idea is the same, so might be the code above is not correct (I will write it in a test and give you the correct code), this is the code for a Map sorting, based on the solution above:
作为应对外星人(2011年11月22日):我使用这个解决方案的地图整数Id和名称,但这个想法是相同的,所以可能是上面的代码是不正确的(我把它写在一个测试,会给你正确的代码),这是一个地图的代码排序,基于上面的解决方案:
package nl.iamit.util;
import java.util.Comparator;
import java.util.Map;
public class Comparators {
public static class MapIntegerStringComparator implements Comparator {
Map<Integer, String> base;
public MapIntegerStringComparator(Map<Integer, String> base) {
this.base = base;
}
public int compare(Object a, Object b) {
int compare = ((String) base.get(a))
.compareTo((String) base.get(b));
if (compare == 0) {
return -1;
}
return compare;
}
}
}
and this is the test class (I just tested it, and this works for the Integer, String Map:
这是测试类(我刚刚测试过,这对于整数,字符串映射是这样的:
package test.nl.iamit.util;
import java.util.HashMap;
import java.util.TreeMap;
import nl.iamit.util.Comparators;
import org.junit.Test;
import static org.junit.Assert.assertArrayEquals;
public class TestComparators {
@Test
public void testMapIntegerStringComparator(){
HashMap<Integer, String> unSoretedMap = new HashMap<Integer, String>();
Comparators.MapIntegerStringComparator bvc = new Comparators.MapIntegerStringComparator(
unSoretedMap);
TreeMap<Integer, String> sorted_map = new TreeMap<Integer, String>(bvc);
//the testdata:
unSoretedMap.put(new Integer(1), "E");
unSoretedMap.put(new Integer(2), "A");
unSoretedMap.put(new Integer(3), "E");
unSoretedMap.put(new Integer(4), "B");
unSoretedMap.put(new Integer(5), "F");
sorted_map.putAll(unSoretedMap);
Object[] targetKeys={new Integer(2),new Integer(4),new Integer(3),new Integer(1),new Integer(5) };
Object[] currecntKeys=sorted_map.keySet().toArray();
assertArrayEquals(targetKeys,currecntKeys);
}
}
here is the code for the Comparator of a Map:
这是地图比较器的代码:
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;
}
}
}
and this is the testcase for this:
这是这个的测试案例:
@Test
public void testMapStringDoubleComparator(){
HashMap<String, Double> unSoretedMap = new HashMap<String, Double>();
Comparators.MapStringDoubleComparator bvc = new Comparators.MapStringDoubleComparator(
unSoretedMap);
TreeMap<String, Double> sorted_map = new TreeMap<String, Double>(bvc);
//the testdata:
unSoretedMap.put("D",new Double(67.3));
unSoretedMap.put("A",new Double(99.5));
unSoretedMap.put("B",new Double(67.4));
unSoretedMap.put("C",new Double(67.5));
unSoretedMap.put("E",new Double(99.5));
sorted_map.putAll(unSoretedMap);
Object[] targetKeys={"D","B","C","E","A"};
Object[] currecntKeys=sorted_map.keySet().toArray();
assertArrayEquals(targetKeys,currecntKeys);
}
of cource you can make this a lot more generic, but I just needed it for 1 case (the Map)
当然,你可以让它更通用一些,但是我只需要一个例子(地图)
#15
10
Instead of using Collections.sort
as some do I'd suggest using Arrays.sort
. Actually what Collections.sort
does is something like this:
而不是使用集合。就像我建议使用Arrays.sort那样。实际上集合。排序是这样的:
public static <T extends Comparable<? super T>> void sort(List<T> list) {
Object[] a = list.toArray();
Arrays.sort(a);
ListIterator<T> i = list.listIterator();
for (int j=0; j<a.length; j++) {
i.next();
i.set((T)a[j]);
}
}
It just calls toArray
on the list and then uses Arrays.sort
. This way all the map entries will be copied three times: once from the map to the temporary list (be it a LinkedList or ArrayList), then to the temporary array and finally to the new map.
它只调用列表中的toArray然后使用Arrays.sort。这样,所有的映射条目将被复制三次:一次从映射到临时列表(无论是LinkedList还是ArrayList),然后是临时数组,最后是新映射。
My solution ommits this one step as it does not create unnecessary LinkedList. Here is the code, generic-friendly and performance-optimal:
我的解决方案省略了这一步,因为它没有创建不必要的LinkedList。这里是代码,一般友好和性能最佳:
public static <K, V extends Comparable<? super V>> Map<K, V> sortByValue(Map<K, V> map)
{
@SuppressWarnings("unchecked")
Map.Entry<K,V>[] array = map.entrySet().toArray(new Map.Entry[map.size()]);
Arrays.sort(array, new Comparator<Map.Entry<K, V>>()
{
public int compare(Map.Entry<K, V> e1, Map.Entry<K, V> e2)
{
return e1.getValue().compareTo(e2.getValue());
}
});
Map<K, V> result = new LinkedHashMap<K, V>();
for (Map.Entry<K, V> entry : array)
result.put(entry.getKey(), entry.getValue());
return result;
}
#16
8
This is a variation of Anthony's answer, which doesn't work if there are duplicate values:
这是Anthony的答案的变体,如果有重复的值,它就不起作用了:
public static <K, V extends Comparable<V>> Map<K, V> sortMapByValues(final Map<K, V> map) {
Comparator<K> valueComparator = new Comparator<K>() {
public int compare(K k1, K k2) {
final V v1 = map.get(k1);
final V v2 = map.get(k2);
/* Not sure how to handle nulls ... */
if (v1 == null) {
return (v2 == null) ? 0 : 1;
}
int compare = v2.compareTo(v1);
if (compare != 0)
{
return compare;
}
else
{
Integer h1 = k1.hashCode();
Integer h2 = k2.hashCode();
return h2.compareTo(h1);
}
}
};
Map<K, V> sortedByValues = new TreeMap<K, V>(valueComparator);
sortedByValues.putAll(map);
return sortedByValues;
}
Note that it's rather up in the air how to handle nulls.
注意,在air中,如何处理nulls是相当困难的。
One important advantage of this approach is that it actually returns a Map, unlike some of the other solutions offered here.
这种方法的一个重要优点是,它实际上返回了一个映射,不像这里提供的其他解决方案。
#17
7
Major problem. If you use the first answer (Google takes you here), change the comparator to add an equal clause, otherwise you cannot get values from the sorted_map by keys:
主要的问题。如果您使用第一个答案(谷歌带您在这里),请更改comparator以添加一个相等的子句,否则您不能通过键获取sorted_map中的值:
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
}
#18
7
There are a lot of answers for this question already, but none provided me what I was looking for, a map implementation that returns keys and entries sorted by the associated value, and maintains this property as keys and values are modified in the map. Two other questions ask for this specifically.
对于这个问题已经有很多答案了,但是没有一个能提供我想要的,一个映射实现,返回键和按关联值排序的条目,并在映射中维护这个属性作为键和值。还有两个问题需要特别说明。
I cooked up a generic friendly example that solves this use case. This implementation does not honor all of the contracts of the Map interface, such as reflecting value changes and removals in the sets return from keySet() and entrySet() in the original object. I felt such a solution would be too large to include in a Stack Overflow answer. If I manage to create a more complete implementation, perhaps I will post it to Github and then to it link in an updated version of this answer.
我编写了一个通用的友好示例来解决这个用例。该实现不尊重映射接口的所有契约,例如在原始对象中从keySet()和entrySet()返回的集合中反映值更改和删除。我觉得这样的解决方案太大了,不能包含在堆栈溢出的答案中。如果我设法创建一个更完整的实现,也许我会将它发布到Github,然后再将其链接到这个答案的更新版本中。
import java.util.*;
/**
* A map where {@link #keySet()} and {@link #entrySet()} return sets ordered
* by associated values based on the the comparator provided at construction
* time. The order of two or more keys with identical values is not defined.
* <p>
* Several contracts of the Map interface are not satisfied by this minimal
* implementation.
*/
public class ValueSortedMap<K, V> extends HashMap<K, V> {
protected Map<V, Collection<K>> valueToKeysMap;
// uses natural order of value object, if any
public ValueSortedMap() {
this((Comparator<? super V>) null);
}
public ValueSortedMap(Comparator<? super V> valueComparator) {
this.valueToKeysMap = new TreeMap<V, Collection<K>>(valueComparator);
}
public boolean containsValue(Object o) {
return valueToKeysMap.containsKey(o);
}
public V put(K k, V v) {
V oldV = null;
if (containsKey(k)) {
oldV = get(k);
valueToKeysMap.get(oldV).remove(k);
}
super.put(k, v);
if (!valueToKeysMap.containsKey(v)) {
Collection<K> keys = new ArrayList<K>();
keys.add(k);
valueToKeysMap.put(v, keys);
} else {
valueToKeysMap.get(v).add(k);
}
return oldV;
}
public void putAll(Map<? extends K, ? extends V> m) {
for (Map.Entry<? extends K, ? extends V> e : m.entrySet())
put(e.getKey(), e.getValue());
}
public V remove(Object k) {
V oldV = null;
if (containsKey(k)) {
oldV = get(k);
super.remove(k);
valueToKeysMap.get(oldV).remove(k);
}
return oldV;
}
public void clear() {
super.clear();
valueToKeysMap.clear();
}
public Set<K> keySet() {
LinkedHashSet<K> ret = new LinkedHashSet<K>(size());
for (V v : valueToKeysMap.keySet()) {
Collection<K> keys = valueToKeysMap.get(v);
ret.addAll(keys);
}
return ret;
}
public Set<Map.Entry<K, V>> entrySet() {
LinkedHashSet<Map.Entry<K, V>> ret = new LinkedHashSet<Map.Entry<K, V>>(size());
for (Collection<K> keys : valueToKeysMap.values()) {
for (final K k : keys) {
final V v = get(k);
ret.add(new Map.Entry<K,V>() {
public K getKey() {
return k;
}
public V getValue() {
return v;
}
public V setValue(V v) {
throw new UnsupportedOperationException();
}
});
}
}
return ret;
}
}
#19
5
This is just too complicated. Maps were not supposed to do such job as sorting them by Value. The easiest way is to create your own Class so it fits your requirement.
这太复杂了。地图不应该是按价值分类的。最简单的方法是创建您自己的类,以满足您的需求。
In example lower you are supposed to add TreeMap a comparator at place where * is. But by java API it gives comparator only keys, not values. All of examples stated here is based on 2 Maps. One Hash and one new Tree. Which is odd.
例如,您应该在*所在的位置添加TreeMap比较器。但是通过java API,它只提供比较器键,而不是值。这里所述的所有示例都基于两个映射。一个哈希和一个新树。这是非常奇怪的。
The example:
示例:
Map<Driver driver, Float time> map = new TreeMap<Driver driver, Float time>(*);
So change the map into a set this way:
所以把地图改成这样:
ResultComparator rc = new ResultComparator();
Set<Results> set = new TreeSet<Results>(rc);
You will create class Results
,
您将创建类结果,
public class Results {
private Driver driver;
private Float time;
public Results(Driver driver, Float time) {
this.driver = driver;
this.time = time;
}
public Float getTime() {
return time;
}
public void setTime(Float time) {
this.time = time;
}
public Driver getDriver() {
return driver;
}
public void setDriver (Driver driver) {
this.driver = driver;
}
}
and the Comparator class:
和比较器类:
public class ResultsComparator implements Comparator<Results> {
public int compare(Results t, Results t1) {
if (t.getTime() < t1.getTime()) {
return 1;
} else if (t.getTime() == t1.getTime()) {
return 0;
} else {
return -1;
}
}
}
This way you can easily add more dependencies.
通过这种方式,您可以轻松地添加更多的依赖项。
And as the last point I'll add simple iterator:
作为最后一点,我将添加简单迭代器:
Iterator it = set.iterator();
while (it.hasNext()) {
Results r = (Results)it.next();
System.out.println( r.getDriver().toString
//or whatever that is related to Driver class -getName() getSurname()
+ " "
+ r.getTime()
);
}
#20
5
Best Approach
最好的方法
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.Set;
import java.util.Map.Entry;
public class OrderByValue {
public static void main(String a[]){
Map<String, Integer> map = new HashMap<String, Integer>();
map.put("java", 20);
map.put("C++", 45);
map.put("Unix", 67);
map.put("MAC", 26);
map.put("Why this kolavari", 93);
Set<Entry<String, Integer>> set = map.entrySet();
List<Entry<String, Integer>> list = new ArrayList<Entry<String, Integer>>(set);
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()).compareTo( o2.getValue() );//Ascending order
//return (o2.getValue()).compareTo( o1.getValue() );//Descending order
}
} );
for(Map.Entry<String, Integer> entry:list){
System.out.println(entry.getKey()+" ==== "+entry.getValue());
}
}}
Output
输出
java ==== 20
MAC ==== 26
C++ ==== 45
Unix ==== 67
Why this kolavari ==== 93
#21
4
Based on @devinmoore code, a map sorting methods using generics and supporting both ascending and descending ordering.
基于@devinmoore代码,一个使用泛型和支持升序和降序排序的地图排序方法。
/**
* Sort a map by it's keys in ascending order.
*
* @return new instance of {@link LinkedHashMap} contained sorted entries of supplied map.
* @author Maxim Veksler
*/
public static <K, V> LinkedHashMap<K, V> sortMapByKey(final Map<K, V> map) {
return sortMapByKey(map, SortingOrder.ASCENDING);
}
/**
* Sort a map by it's values in ascending order.
*
* @return new instance of {@link LinkedHashMap} contained sorted entries of supplied map.
* @author Maxim Veksler
*/
public static <K, V> LinkedHashMap<K, V> sortMapByValue(final Map<K, V> map) {
return sortMapByValue(map, SortingOrder.ASCENDING);
}
/**
* Sort a map by it's keys.
*
* @param sortingOrder {@link SortingOrder} enum specifying requested sorting order.
* @return new instance of {@link LinkedHashMap} contained sorted entries of supplied map.
* @author Maxim Veksler
*/
public static <K, V> LinkedHashMap<K, V> sortMapByKey(final Map<K, V> map, final SortingOrder sortingOrder) {
Comparator<Map.Entry<K, V>> comparator = new Comparator<Entry<K,V>>() {
public int compare(Entry<K, V> o1, Entry<K, V> o2) {
return comparableCompare(o1.getKey(), o2.getKey(), sortingOrder);
}
};
return sortMap(map, comparator);
}
/**
* Sort a map by it's values.
*
* @param sortingOrder {@link SortingOrder} enum specifying requested sorting order.
* @return new instance of {@link LinkedHashMap} contained sorted entries of supplied map.
* @author Maxim Veksler
*/
public static <K, V> LinkedHashMap<K, V> sortMapByValue(final Map<K, V> map, final SortingOrder sortingOrder) {
Comparator<Map.Entry<K, V>> comparator = new Comparator<Entry<K,V>>() {
public int compare(Entry<K, V> o1, Entry<K, V> o2) {
return comparableCompare(o1.getValue(), o2.getValue(), sortingOrder);
}
};
return sortMap(map, comparator);
}
@SuppressWarnings("unchecked")
private static <T> int comparableCompare(T o1, T o2, SortingOrder sortingOrder) {
int compare = ((Comparable<T>)o1).compareTo(o2);
switch (sortingOrder) {
case ASCENDING:
return compare;
case DESCENDING:
return (-1) * compare;
}
return 0;
}
/**
* Sort a map by supplied comparator logic.
*
* @return new instance of {@link LinkedHashMap} contained sorted entries of supplied map.
* @author Maxim Veksler
*/
public static <K, V> LinkedHashMap<K, V> sortMap(final Map<K, V> map, final Comparator<Map.Entry<K, V>> comparator) {
// Convert the map into a list of key,value pairs.
List<Map.Entry<K, V>> mapEntries = new LinkedList<Map.Entry<K, V>>(map.entrySet());
// Sort the converted list according to supplied comparator.
Collections.sort(mapEntries, comparator);
// Build a new ordered map, containing the same entries as the old map.
LinkedHashMap<K, V> result = new LinkedHashMap<K, V>(map.size() + (map.size() / 20));
for(Map.Entry<K, V> entry : mapEntries) {
// We iterate on the mapEntries list which is sorted by the comparator putting new entries into
// the targeted result which is a sorted map.
result.put(entry.getKey(), entry.getValue());
}
return result;
}
/**
* Sorting order enum, specifying request result sort behavior.
* @author Maxim Veksler
*
*/
public static enum SortingOrder {
/**
* Resulting sort will be from smaller to biggest.
*/
ASCENDING,
/**
* Resulting sort will be from biggest to smallest.
*/
DESCENDING
}
#22
4
Here is an OO solution (i.e., doesn't use static
methods):
这里有一个OO解决方案(即:,不使用静态方法):
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
public class SortableValueMap<K, V extends Comparable<V>>
extends LinkedHashMap<K, V> {
public SortableValueMap() { }
public SortableValueMap( Map<K, V> map ) {
super( map );
}
public void sortByValue() {
List<Map.Entry<K, V>> list = new LinkedList<Map.Entry<K, V>>( entrySet() );
Collections.sort( list, new Comparator<Map.Entry<K, V>>() {
public int compare( Map.Entry<K, V> entry1, Map.Entry<K, V> entry2 ) {
return entry1.getValue().compareTo( entry2.getValue() );
}
});
clear();
for( Map.Entry<K, V> entry : list ) {
put( entry.getKey(), entry.getValue() );
}
}
private static void print( String text, Map<String, Double> map ) {
System.out.println( text );
for( String key : map.keySet() ) {
System.out.println( "key/value: " + key + "/" + map.get( key ) );
}
}
public static void main( String[] args ) {
SortableValueMap<String, Double> map =
new SortableValueMap<String, Double>();
map.put( "A", 67.5 );
map.put( "B", 99.5 );
map.put( "C", 82.4 );
map.put( "D", 42.0 );
print( "Unsorted map", map );
map.sortByValue();
print( "Sorted map", map );
}
}
Hereby donated to the public domain.
特此捐赠给公共领域。
#23
4
Afaik the most cleaner way is utilizing collections to sort map on value:
Afaik最清洁的方法是利用集合来分类地图的价值:
Map<String, Long> map = new HashMap<String, Long>();
// populate with data to sort on Value
// use datastructure designed for sorting
Queue queue = new PriorityQueue( map.size(), new MapComparable() );
queue.addAll( map.entrySet() );
// get a sorted map
LinkedHashMap<String, Long> linkedMap = new LinkedHashMap<String, Long>();
for (Map.Entry<String, Long> entry; (entry = queue.poll())!=null;) {
linkedMap.put(entry.getKey(), entry.getValue());
}
public static class MapComparable implements Comparator<Map.Entry<String, Long>>{
public int compare(Entry<String, Long> e1, Entry<String, Long> e2) {
return e1.getValue().compareTo(e2.getValue());
}
}
#24
4
Since TreeMap<> does not work for values that can be equal, I used this:
因为TreeMap<>不适用于可以相等的值,所以我使用了这个:
private <K, V extends Comparable<? super V>> List<Entry<K, V>> sort(Map<K, V> map) {
List<Map.Entry<K, V>> list = new LinkedList<Map.Entry<K, V>>(map.entrySet());
Collections.sort(list, new Comparator<Map.Entry<K, V>>() {
public int compare(Map.Entry<K, V> o1, Map.Entry<K, V> o2) {
return o1.getValue().compareTo(o2.getValue());
}
});
return list;
}
You might want to put list in a LinkedHashMap, but if you're only going to iterate over it right away, that's superfluous...
你可能想把列表放在LinkedHashMap中,但是如果你只打算在上面迭代,那是多余的…
#25
4
Some simple changes in order to have a sorted map with pairs that have duplicate values. In the compare method (class ValueComparator) when values are equal do not return 0 but return the result of comparing the 2 keys. Keys are distinct in a map so you succeed to keep duplicate values (which are sorted by keys by the way). So the above example could be modified like this:
一些简单的更改,以便使用具有重复值的对进行排序映射。在比较方法(class ValueComparator)中,当值相等时,不返回0,但返回比较两个键的结果。键在映射中是不同的,所以您成功地保留了重复的值(顺便说一下,这些值是按键排序的)。上面的例子可以这样修改:
public int compare(Object a, Object b) {
if((Double)base.get(a) < (Double)base.get(b)) {
return 1;
} else if((Double)base.get(a) == (Double)base.get(b)) {
return ((String)a).compareTo((String)b);
} else {
return -1;
}
}
}
#26
4
For sure the solution of Stephen is really great, but for those who can't use Guava:
当然,斯蒂芬的解决方案真的很棒,但是对于那些不能使用番石榴的人来说:
Here's my solution for sorting by value a map. This solution handle the case where there are twice the same value etc...
这是我的解决方案,对地图进行排序。这个解决方案处理的情况是相同值的两倍。
// If you want to sort a map by value, and if there can be twice the same value:
// here is your original map
Map<String,Integer> mapToSortByValue = new HashMap<String, Integer>();
mapToSortByValue.put("A", 3);
mapToSortByValue.put("B", 1);
mapToSortByValue.put("C", 3);
mapToSortByValue.put("D", 5);
mapToSortByValue.put("E", -1);
mapToSortByValue.put("F", 1000);
mapToSortByValue.put("G", 79);
mapToSortByValue.put("H", 15);
// Sort all the map entries by value
Set<Map.Entry<String,Integer>> set = new TreeSet<Map.Entry<String,Integer>>(
new Comparator<Map.Entry<String,Integer>>(){
@Override
public int compare(Map.Entry<String,Integer> obj1, Map.Entry<String,Integer> obj2) {
Integer val1 = obj1.getValue();
Integer val2 = obj2.getValue();
// DUPLICATE VALUE CASE
// If the values are equals, we can't return 0 because the 2 entries would be considered
// as equals and one of them would be deleted (because we use a set, no duplicate, remember!)
int compareValues = val1.compareTo(val2);
if ( compareValues == 0 ) {
String key1 = obj1.getKey();
String key2 = obj2.getKey();
int compareKeys = key1.compareTo(key2);
if ( compareKeys == 0 ) {
// what you return here will tell us if you keep REAL KEY-VALUE duplicates in your set
// if you want to, do whatever you want but do not return 0 (but don't break the comparator contract!)
return 0;
}
return compareKeys;
}
return compareValues;
}
}
);
set.addAll(mapToSortByValue.entrySet());
// OK NOW OUR SET IS SORTED COOL!!!!
// And there's nothing more to do: the entries are sorted by value!
for ( Map.Entry<String,Integer> entry : set ) {
System.out.println("Set entries: " + entry.getKey() + " -> " + entry.getValue());
}
// But if you add them to an hashmap
Map<String,Integer> myMap = new HashMap<String,Integer>();
// When iterating over the set the order is still good in the println...
for ( Map.Entry<String,Integer> entry : set ) {
System.out.println("Added to result map entries: " + entry.getKey() + " " + entry.getValue());
myMap.put(entry.getKey(), entry.getValue());
}
// But once they are in the hashmap, the order is not kept!
for ( Integer value : myMap.values() ) {
System.out.println("Result map values: " + value);
}
// Also this way doesn't work:
// Logic because the entryset is a hashset for hashmaps and not a treeset
// (and even if it was a treeset, it would be on the keys only)
for ( Map.Entry<String,Integer> entry : myMap.entrySet() ) {
System.out.println("Result map entries: " + entry.getKey() + " -> " + entry.getValue());
}
// CONCLUSION:
// If you want to iterate on a map ordered by value, you need to remember:
// 1) Maps are only sorted by keys, so you can't sort them directly by value
// 2) So you simply CAN'T return a map to a sortMapByValue function
// 3) You can't reverse the keys and the values because you have duplicate values
// This also means you can't neither use Guava/Commons bidirectionnal treemaps or stuff like that
// SOLUTIONS
// So you can:
// 1) only sort the values which is easy, but you loose the key/value link (since you have duplicate values)
// 2) sort the map entries, but don't forget to handle the duplicate value case (like i did)
// 3) if you really need to return a map, use a LinkedHashMap which keep the insertion order
The exec: http://www.ideone.com/dq3Lu
exec:http://www.ideone.com/dq3Lu
The output:
输出:
Set entries: E -> -1
Set entries: B -> 1
Set entries: A -> 3
Set entries: C -> 3
Set entries: D -> 5
Set entries: H -> 15
Set entries: G -> 79
Set entries: F -> 1000
Added to result map entries: E -1
Added to result map entries: B 1
Added to result map entries: A 3
Added to result map entries: C 3
Added to result map entries: D 5
Added to result map entries: H 15
Added to result map entries: G 79
Added to result map entries: F 1000
Result map values: 5
Result map values: -1
Result map values: 1000
Result map values: 79
Result map values: 3
Result map values: 1
Result map values: 3
Result map values: 15
Result map entries: D -> 5
Result map entries: E -> -1
Result map entries: F -> 1000
Result map entries: G -> 79
Result map entries: A -> 3
Result map entries: B -> 1
Result map entries: C -> 3
Result map entries: H -> 15
Hope it will help some folks
希望它能帮助一些人。
#27
4
I've merged the solutions of user157196 and Carter Page:
我已经合并了user157196和Carter Page的解决方案:
class MapUtil {
public static <K, V extends Comparable<? super V>> Map<K, V> sortByValue( Map<K, V> map ){
ValueComparator<K,V> bvc = new ValueComparator<K,V>(map);
TreeMap<K,V> sorted_map = new TreeMap<K,V>(bvc);
sorted_map.putAll(map);
return sorted_map;
}
}
class ValueComparator<K, V extends Comparable<? super V>> implements Comparator<K> {
Map<K, V> base;
public ValueComparator(Map<K, V> base) {
this.base = base;
}
public int compare(K a, K b) {
int result = (base.get(a).compareTo(base.get(b)));
if (result == 0) result=1;
// returning 0 would merge keys
return result;
}
}
#28
3
Depending on the context, using java.util.LinkedHashMap<T>
which rememebers the order in which items are placed into the map. Otherwise, if you need to sort values based on their natural ordering, I would recommend maintaining a separate List which can be sorted via Collections.sort()
.
取决于上下文,使用java.util。LinkedHashMap
#29
3
If you have duplicate keys and only a small set of data (<1000) and your code is not performance critical you can just do the following:
如果您有重复的密钥,并且只有一小部分数据(<1000),并且您的代码不是性能关键的,您可以执行以下操作:
Map<String,Integer> tempMap=new HashMap<String,Integer>(inputUnsortedMap);
LinkedHashMap<String,Integer> sortedOutputMap=new LinkedHashMap<String,Integer>();
for(int i=0;i<inputUnsortedMap.size();i++){
Map.Entry<String,Integer> maxEntry=null;
Integer maxValue=-1;
for(Map.Entry<String,Integer> entry:tempMap.entrySet()){
if(entry.getValue()>maxValue){
maxValue=entry.getValue();
maxEntry=entry;
}
}
tempMap.remove(maxEntry.getKey());
sortedOutputMap.put(maxEntry.getKey(),maxEntry.getValue());
}
inputUnsortedMap is the input to the code.
inputUnsortedMap是代码的输入。
The variable sortedOutputMap will contain the data in decending order when iterated over. To change order just change > to a < in the if statement.
变量sortedOutputMap将在迭代结束时包含decending order中的数据。若要更改顺序,只需将>更改为if语句中的一个<。
Is not the fastest sort but does the job without any additional dependencies.
并不是最快的排序,但是没有任何附加的依赖项。
#30
3
You can try Guava's multimaps:
你可以试试番石榴的multimaps:
TreeMap<Integer, Collection<String>> sortedMap = new TreeMap<>(
Multimaps.invertFrom(Multimaps.forMap(originalMap),
ArrayListMultimap.<Integer, String>create()).asMap());
As a result you get a map from original values to collections of keys that correspond to them. This approach can be used even if there are multiple keys for the same value.
因此,您可以从原始值到对应于它们的键集合得到一个映射。即使有相同值的多个键,也可以使用此方法。