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

Java 可以按值的顺序迭代的映射,java,collections,map,guava,apache-commons,Java,Collections,Map,Guava,Apache Commons,我需要一个可以按其值的降序迭代的映射。Apache Commons或Guava之类的标准库是否提供了这种映射?我认为Apache Commons集合的使用应该使这成为可能,可能是通过迭代来自inverseBIMAP()的返回 但我认为这不允许重复值——正如名字所说,结构只是基于保留两棵树,这是唯一有意义的事情,因为地图中的值对地图结构没有意义。把值也放在树集中怎么样 for(;;) { yourMap.put(key,value); } SortedSet sortedValues = new

我需要一个可以按其值的降序迭代的映射。Apache Commons或Guava之类的标准库是否提供了这种映射?

我认为Apache Commons集合的使用应该使这成为可能,可能是通过迭代来自
inverseBIMAP()的返回


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

把值也放在树集中怎么样

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


我会把条目放在列表上并进行排序。我不记得有任何地图可以按值排序,只能按键排序。您可以使用番石榴的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());
            }
        });

    }
publicstaticvoidmain(字符串[]args){
Map Map=newhashmap(){{
卖出(“键1”、“值1”);
卖出(“第2键”、“第3值”);
卖出(“第3项”、“第4项”);
卖出(“第4键”、“第2值”);
}};
列表条目=新的ArrayList(map.entrySet());
Collections.sort(条目,新的Comparator(){
@凌驾
公共整数比较(条目o1,
入口(氧气){
如果(o1.getValue()==null&&o2.getValue()==null)返回0;
if(o1.getValue()==null)返回-1;//最后为null
返回-o1.getValue().compareTo(o2.getValue());
}
});
}

我会用番石榴做如下:

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
Ordering entryOrdering=Ordering.from(valueComparator)
.onResultOf(新函数(){
公共值应用(条目){
返回条目.getValue();
}
}).reverse();
//按所需顺序输入所需条目。按此顺序将它们放入不可变映射中。
ImmutableMap.Builder=ImmutableMap.Builder();
对于(条目:
entryOrdering.sortedCopy(map.entrySet()){
put(entry.getKey(),entry.getValue());
}
返回builder.build();
//ImmutableMap按所需顺序对条目进行迭代

我认为您必须自己实现这样一个映射。幸运的是,这对番石榴来说应该不是什么大问题:

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()));
  }
}
公共类SortedValueMap扩展了ForwardingMap{
私有映射委托=newHashMap();
私人比较人;价值比较人;
公共静态SortedValueMap reverse(){
返回新的SortedValueMap(Ordering.natural().reverse());
}
公共静态SortedValueMap创建(Comparator valueComparator){
返回新的SortedValueMap(valueComparator);
}
受保护的分类值映射(比较器值比较器){
this.valueComparator=checkNotNull(valueComparator);
}
@凌驾
受保护的映射委托(){
返回代表;
}
@凌驾
公共集密钥集(){
返回新的StandardKeySet();
}
@凌驾
公共集入口集(){
树集结果=新树集(新比较器(){
@凌驾
公共整数比较(Map.Entry o1,Map.Entry o2){
返回ComparisonChain.start()
.compare(o1.getValue()、o2.getValue()、valueComparator)
.compare(o1.getKey()、o2.getKey()、Ordering.Arbital())
.result();
}
});
result.addAll(Collections.unmodifiableMap(delegate.entrySet());
返回结果;
}
@凌驾
公共集合值(){
返回新的标准值();
}
公共静态void main(字符串[]args){
SortedValueMap svm=SortedValueMap.reverse();
svm.put(“foo”,“1”);
svm.put(“条”,“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());
}
}

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

对于番石榴,甚至有比@LoisWasserman的anwer更干净的方法-使用排序与:

或者如果值不可比较

Ordering.fromComparator(yourComparator).reverse().nullsLast().onResultOf(Functions.forMap(map, null))
示例(第一个选项-自然排序):

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

编辑

如果存在相同的值(更确切地说,如果存在两个值,
Comparator.compare(String v1,String v2)
返回0),ImmutableSortedMap将抛出异常。排序不能返回,因此,如果两个值相等(键不应该相等),则应首先按值排序map,然后按键排序,方法是使用:


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

private Map-sortedByValue(映射theMap){
最终订购=
Ordering.natural().reverse().nullsLast().onResultOf(Functions.forMap(theMap,null));
返回ImmutableSortedMap.copyOf(映射,排序);
}

现在可以使用以下方法在一行中完成此操作:

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

标准Java库有一个扩展的
Map
接口,被称为SortedMap:然后你可以选择
SortedMap
接口的一个具体实现。我觉得奇怪的是,你想要值的降序-你真的想要那个还是指键?@nd:是的,我确定我真的想要想要分类地图的顺序是键,而不是值——它在文档的第一行有说明。你不需要两棵树。你可以有一个
Map
作为键值,一个有序的
List
值列表(或者
Map.Entry
s,如果你需要的话)。@yshavit:如果你有列表结构,你可以
Ordering.natural().reverse().nullsLast().onResultOf(Functions.forMap(map, null))
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}
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}
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);
}