【问题标题】:Split map into two lists将地图拆分为两个列表
【发布时间】:2016-07-26 22:26:14
【问题描述】:

我有一个Map<String,Integer>,它按如下值排序:

set = map.entrySet();
list = new ArrayList<Map.Entry<String, Integer»(set);
Collections.sort( list, (o1, o2) -> (o2.getValue()).compareTo( o1.getValue() ));

我已经有一个来自该地图的排序整数列表:

word_used = new ArrayList<Integer>(map.values() 
.stream() 
.sorted() 
.collect(Collectors.toList())); 
Collections.reverse(word_used); 

但是我怎样才能得到一个字符串列表,它将被排序等于 Map(按值)?

我的意思是,如果我有一张包含物品的地图:

map.put("eggs",1500); 
map.put("echo",150); 
map.put("foo",320); 
map.put("smt",50); 

并按如下方式排序:

eggs : 1500 
foo : 320 
echo : 150 
smt : 50 

我需要获取 2 个列表:

eggs 
foo 
echo 
smt

1500 
320 
150 
50

【问题讨论】:

  • word_list = new ArrayList&lt;String&gt;(map.keySet() .stream() .sorted() .collect(Collectors.toList())); 工作吗?
  • 请注意,说 Map 已排序是一种误导。构造和排序Map 的条目的List 不会影响Map 集合视图的迭代顺序。您只有一个已排序的List——尽管如此,它还是很有用的。

标签: java list dictionary


【解决方案1】:

您可以使用map() 将投影添加到您的流中,如下所示:

List<String> word_used = map.entrySet() 
        .stream() 
        .sorted(Comparator.comparing(Map.Entry<String,Integer>::getValue).reversed())
        .map(Map.Entry<String,Integer>::getKey)
        .collect(Collectors.toList());

List<Integer> ints_used = map.entrySet() 
        .stream() 
        .sorted(Comparator.comparing(Map.Entry<String,Integer>::getValue).reversed())
        .map(Map.Entry<String,Integer>::getValue)
        .collect(Collectors.toList());

Demo 1

请注意,这种方法会排序两次。您可以捕获条目一次,然后从该临时列表中投影,如下所示:

List<Map.Entry<String,Integer>> sortedList = map
        .entrySet() 
        .stream() 
        .sorted(Comparator.comparing(Map.Entry<String,Integer>::getValue).reversed())
        .collect(Collectors.toList());

List<String> word_used = sortedList
        .stream()
        .map(Map.Entry<String,Integer>::getKey)
        .collect(Collectors.toList());

List<Integer> ints_used = sortedList
        .stream()
        .map(Map.Entry<String,Integer>::getValue)
        .collect(Collectors.toList());

Demo 2

【讨论】:

    【解决方案2】:

    您已经拥有映射Entrys 的List(由变量list 引用),按照您描述的顺序按值排序。您可以从这些对象中构造新的、单独的 Lists 键和值。非流版本可能是:

    List<String> words = new ArrayList<>();
    List<Integer> values = new ArrayList<>();
    
    for (Map.Entry<String, Integer> entry : list) {
        words.add(entry.getKey());
        values.add(entry.getValue());
    }
    

    【讨论】:

      【解决方案3】:

      使用这种方法可能只排序和迭代一次:

          List<String> word_used = new ArrayList<String>();
          List<Integer> ints_used = map.entrySet().stream() 
              .sorted(Comparator.comparing(Map.Entry<String,Integer>::getValue).reversed())
              .peek(e -> word_used.add(e.getKey()))
              .map(Map.Entry::getValue)
              .collect(Collectors.toList());
      

      【讨论】:

        【解决方案4】:

        您可以将 TreeMap 与比较值而不是键的比较器一起使用,然后在其上调用 keys() 和 values()。

        见:https://docs.oracle.com/javase/8/docs/api/java/util/TreeMap.html

        【讨论】: