我需要一个可以按其值递减顺序迭代的地图。是否有像Apache Commons或Guava这样的标准库提供这种地图?
答案 0 :(得分:13)
我会用Guava做到这一点:
Ordering<Map.Entry<Key, Value>> entryOrdering = Ordering.from(valueComparator)
.onResultOf(new Function<Entry<Key, Value>, Value>() {
public Value apply(Entry<Key, Value> entry) {
return entry.getValue();
}
}).reverse();
// Desired entries in desired order. Put them in an ImmutableMap in this order.
ImmutableMap.Builder<Key, Value> builder = ImmutableMap.builder();
for (Entry<Key, Value> entry :
entryOrdering.sortedCopy(map.entrySet())) {
builder.put(entry.getKey(), entry.getValue());
}
return builder.build();
// ImmutableMap iterates over the entries in the desired order
答案 1 :(得分:11)
使用番石榴,甚至比@ LoisWasserman的使用方式更清晰 - 使用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<String, String> map = ImmutableMap.of(
"key 1", "value 1",
"key 2", "value 2",
"key 3", "another value",
"key 4", "zero value");
final Ordering<String> 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会抛出异常。订购一定不能返回,所以你应该首先按值排序地图,如果两个值相等(键不应该相等),则应使用Ordering.compound
final Map<String, String> map = ImmutableMap.of(
"key 1", "value 1",
"key 2", "value 2",
"key 3", "zero value",
"key 4", "zero value");
final Ordering<String> 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}
答案 2 :(得分:1)
通过降序值获取地图的不可变副本的简单方法。如果您想升序,请移除对reverse()
的来电。需要Google Guava。
private Map<String, String> mapSortedByValues(Map<String, String> theMap) {
final Ordering<String> ordering =
Ordering.natural().reverse().nullsLast().onResultOf(Functions.forMap(theMap, null));
return ImmutableSortedMap.copyOf(theMap, ordering);
}
答案 3 :(得分:0)
我认为Apache Commons Collections的DualTreeBidiMap
应该可以通过迭代inverseBidiMap()
的返回来实现这一点。
但我不认为这允许重复值 - 正如名称所说,结构只是基于保留两个树,这是唯一有意义的事情,因为地图对地图结构没有意义。
答案 4 :(得分:0)
如何将值也放在TreeSet中?
for(;;) { yourMap.put(key,value); }
SortedSet sortedValues = new TreeSet(yourMap.values());
或
SortedSet sortedValues = new TreeSet();
for(;;)
{
yourMap.put(key,value);
sortedValued.add(value);
}
答案 5 :(得分:0)
我会在列表中添加条目并对其进行排序。我不记得任何可以按值排序的地图,只能按键排序。您可以使用Guava中的BiMap,但它需要值唯一性。
示例:
public static void main(String[] args) {
Map<String, String> map = new HashMap<String, String>() {{
put("key1", "value1");
put("key2", "value3");
put("key3", "value4");
put("key4", "value2");
}};
List<Map.Entry<String, String>> entries = new ArrayList<>(map.entrySet());
Collections.sort(entries, new Comparator<Map.Entry<String, String>>() {
@Override
public int compare(Entry<String, String> o1,
Entry<String, String> o2) {
if (o1.getValue() == null && o2.getValue() == null) return 0;
if (o1.getValue() == null) return -1; //Nulls last
return - o1.getValue().compareTo(o2.getValue());
}
});
}
答案 6 :(得分:0)
我认为你必须推出自己的这种地图的实现。幸运的是,它对Guava来说不应该是一个大问题:
public class SortedValueMap<K, V> extends ForwardingMap<K, V> {
private Map<K, V> delegate = newHashMap();
private Comparator<V> valueComparator;
public static <K, V extends Comparable<V>> SortedValueMap<K, V> reverse() {
return new SortedValueMap<K, V>(Ordering.<V> natural().reverse());
}
public static <K, V> SortedValueMap<K, V> create(Comparator<V> valueComparator) {
return new SortedValueMap<K, V>(valueComparator);
}
protected SortedValueMap(Comparator<V> valueComparator) {
this.valueComparator = checkNotNull(valueComparator);
}
@Override
protected Map<K, V> delegate() {
return delegate;
}
@Override
public Set<K> keySet() {
return new StandardKeySet();
}
@Override
public Set<Map.Entry<K, V>> entrySet() {
TreeSet<Map.Entry<K, V>> result = newTreeSet(new Comparator<Map.Entry<K, V>>() {
@Override
public int compare(Map.Entry<K, V> o1, Map.Entry<K, V> 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<V> values() {
return new StandardValues();
}
public static void main(String[] args) {
SortedValueMap<String, String> 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
的原因。
答案 7 :(得分:0)
现在可以使用Java 8 Streams:
在一行中完成此操作map.entrySet().stream()
.sorted(Comparator.comparing(Map.Entry::getValue))
.forEach(...);