可以按值的顺序迭代的映射

我需要一个可以按其值的递减顺序迭代的Map。 是否有像Apache Commons或Guava这样的标准库提供这种地图?

我会用番石榴做到这一点如下:

 Ordering> entryOrdering = Ordering.from(valueComparator) .onResultOf(new Function, Value>() { public Value apply(Entry entry) { return entry.getValue(); } }).reverse(); // Desired entries in desired order. Put them in an ImmutableMap in this order. ImmutableMap.Builder builder = ImmutableMap.builder(); for (Entry entry : entryOrdering.sortedCopy(map.entrySet())) { builder.put(entry.getKey(), entry.getValue()); } return builder.build(); // ImmutableMap iterates over the entries in the desired order 

使用番石榴,甚至比@ LoisWasserman的anwer更清洁 – 使用Ordering结合Functions.forMap

 Ordering.natural().reverse().nullsLast().onResultOf(Functions.forMap(map, null)) 

或者如果值不是Comparable

 Ordering.fromComparator(yourComparator).reverse().nullsLast().onResultOf(Functions.forMap(map, null)) 

一个例子(第一个选项 – 自然排序):

 final Map map = ImmutableMap.of( "key 1", "value 1", "key 2", "value 2", "key 3", "another value", "key 4", "zero value"); final Ordering naturalReverseValueOrdering = Ordering.natural().reverse().nullsLast().onResultOf(Functions.forMap(map, null)); System.out.println(ImmutableSortedMap.copyOf(map, naturalReverseValueOrdering)); 

输出:

 {key 4=zero value, key 2=value 2, key 1=value 1, key 3=another value} 

(我在这里使用ImmutableSortedMap ,但如果需要可变性,也可以使用TreeMap 。)

编辑

如果存在相同的值(更确切地说,如果有两个值, Comparator.compare(String v1, String v2)返回0),则ImmutableSortedMap会抛出exception。 订购不得返回,因此即使您使用Ordering.compound,您应首先按值排序映射,如果两个值相等(键不应相等),则按键Ordering.compound

 final Map map = ImmutableMap.of( "key 1", "value 1", "key 2", "value 2", "key 3", "zero value", "key 4", "zero value"); final Ordering reverseValuesAndNaturalKeysOrdering = Ordering.natural().reverse().nullsLast().onResultOf(Functions.forMap(map, null)) // natural for values .compound(Ordering.natural()); // secondary - natural ordering of keys System.out.println(ImmutableSortedMap.copyOf(map, reverseValuesAndNaturalKeysOrdering)); 

打印:

 {key 3=zero value, key 4=zero value, key 2=value 2, key 1=value 1} 

获取地图的不可变副本的简单方法,按降序值排序。 如果要升序,请取消对reverse()的调用。 需要谷歌番石榴 。

 private Map mapSortedByValues(Map theMap) { final Ordering ordering = Ordering.natural().reverse().nullsLast().onResultOf(Functions.forMap(theMap, null)); return ImmutableSortedMap.copyOf(theMap, ordering); } 

我认为Apache Commons Collections的DualTreeBidiMap应该可以通过迭代inverseBidiMap()的返回来实现这一点。

但我不认为这允许重复值 – 正如名称所说,结构只是基于保留棵树,这是唯一有意义的事情,因为地图中的值对地图结构没有意义。

如何将值也放在TreeSet中?

 for(;;) { yourMap.put(key,value); } SortedSet sortedValues = new TreeSet(yourMap.values()); 

要么

 SortedSet sortedValues = new TreeSet(); for(;;) { yourMap.put(key,value); sortedValued.add(value); } 

我把条目放在列表上并对其进行排序。 我不记得任何可以按值排序的地图,只能按键排序。 您可以使用Guava中的BiMap,但它需要值唯一性。

例:

  public static void main(String[] args) { Map map = new HashMap() {{ put("key1", "value1"); put("key2", "value3"); put("key3", "value4"); put("key4", "value2"); }}; List> entries = new ArrayList<>(map.entrySet()); Collections.sort(entries, new Comparator>() { @Override public int compare(Entry o1, Entry o2) { if (o1.getValue() == null && o2.getValue() == null) return 0; if (o1.getValue() == null) return -1; //Nulls last return - o1.getValue().compareTo(o2.getValue()); } }); } 

我认为你必须推出自己的这种地图的实现。 幸运的是,它不应该是番石榴的问题:

 public class SortedValueMap extends ForwardingMap { private Map delegate = newHashMap(); private Comparator valueComparator; public static > SortedValueMap reverse() { return new SortedValueMap(Ordering. natural().reverse()); } public static  SortedValueMap create(Comparator valueComparator) { return new SortedValueMap(valueComparator); } protected SortedValueMap(Comparator valueComparator) { this.valueComparator = checkNotNull(valueComparator); } @Override protected Map delegate() { return delegate; } @Override public Set keySet() { return new StandardKeySet(); } @Override public Set> entrySet() { TreeSet> result = newTreeSet(new Comparator>() { @Override public int compare(Map.Entry o1, Map.Entry o2) { return ComparisonChain.start() .compare(o1.getValue(), o2.getValue(), valueComparator) .compare(o1.getKey(), o2.getKey(), Ordering.arbitrary()) .result(); } }); result.addAll(Collections.unmodifiableMap(delegate).entrySet()); return result; } @Override public Collection values() { return new StandardValues(); } public static void main(String[] args) { SortedValueMap svm = SortedValueMap.reverse(); svm.put("foo", "1"); svm.put("bar", "3"); svm.put("baz", "2"); System.out.println(Joiner.on(", ").withKeyValueSeparator("=").join(svm)); System.out.println(Joiner.on(", ").join(svm.values())); System.out.println(Joiner.on(", ").join(svm.keySet())); } } 

此实现中不存在失败快速迭代器; 如果需要,请自行添加。 还请注意,通过Map.Entry.setValue设置值会导致对排序顺序的破坏,这就是我在条目集中使用unmodifyableMap原因。

现在可以使用Java 8 Streams在一行中完成此操作:

 map.entrySet().stream() .sorted(Comparator.comparing(Map.Entry::getValue)) .forEach(...);