如何高效地将 Map<String, Integer> 按值从大到小排序成 List<String>?

3
我有一个ConcurrentMap,我想从中获取一个List,其中String与最大的Integer映射在一起,第二大的映射在第二个位置,以此类推。
目前我的做法类似于以下步骤: 1. 循环遍历map的keySet 2. 在该循环内,再循环遍历已排序的List 3. 保持循环,直到key String对应的值小于“sorted” List的第i个元素,并插入它。
现在这个方法可以工作,但我怀疑它不是很有效率。Java 8有任何内置的排序算法可以帮助我吗?

1
如果您展示代码而不是描述它,那么理解您正在做什么会更容易。 - assylias
抱歉,我还没有测试我的代码,不想用可能不正确的代码来困扰其他人。 - Rogue
这也是数据结构中的一个问题。我会创建一个反向映射 - 即从整数到字符串列表的映射。不使用HashMap,因为键的顺序基于哈希函数,而是使用TreeMap - 因此在将它们插入到映射时,键实际上是排序的。然后,我可以遍历已按其值排序的键,获取与该整数键匹配的字符串列表,并将其连接到主字符串列表中,这就是您需要的最终列表。 - SomethingSomething
虽然你可能最好使用内置的方法来完成它,就像答案中所描述的那样。我的算法正在重新发明轮子。 - SomethingSomething
3个回答

9
使用流,你可以像这样编写它:
List<String> sorted = map.entrySet().stream()
                         .sorted(reverseOrder(comparing(Entry::getValue)))
                         .map(Entry::getKey)
                         .collect(toList());

或者像Holger评论的那样:
List<String> sorted = map.entrySet().stream()
                         .sorted(comparingByValue(reverseOrder()))
                         .map(Entry::getKey)
                         .collect(toList());

注意静态导入:
import static java.util.Collections.reverseOrder;
import static java.util.Comparator.comparing;
import static java.util.stream.Collectors.toList;

我不确定这是否比您的方法更有效,但您可以对两种方法进行分析并根据实际测量结果进行决策。


短小精悍,使用Java 8,非常好!谢谢! - Rogue
1
抱歉打扰您了。我想知道为什么.sorted(Comparator.comparing(Map.Entry::getValue))可以编译/正常工作,但是.sorted(Comparator.comparing(Map.Entry::getValue).reversed())却无法编译,声称getValue不需要参数,但它找到了Object。如果我明确地向Map.Entry<String,Integer>添加泛型类型,它也会编译。您认为我应该就这个类型推断问题创建一个单独的问题,还是我错过了一些已经在SO问题上解释过的显而易见的事实? - Pshemo
1
@Pshemo 是的,这很烦人 - 我认为这是由于类型推断在方法链接方面效率不高所致... 参见:https://dev59.com/zF8e5IYBdhLWcg3w-OUn - assylias
1
谢谢。那个问题非常接近我所遇到的问题。因此,现在我可能会使用您的方法或者comparing(extractor, comparator),例如.sorted(Comparator.comparing(Map.Entry::getValue, Comparator.reverseOrder())),这也可以正常工作,无需显式添加泛型类型。 - Pshemo
2
@Pshemo:更容易了.sorted(comparingByValue(reverseOrder())) - Holger

1
是的,可以这样做:

Yes, it does. You could do something like this:

ConcurrentMap<String, Integer> map = /* something */;

// entrySet just returns a view of the entries, so copy it into a new List
List<Map.Entry<String, Integer>> entries = new ArrayList<>(yourMap.entrySet());

// sort entries by their int values
Collections.sort(entries, (entry1, entry2) -> Integer.compare(entry1.getValue(), entry2.getValue()));

// copy just the keys into a new List
List<String> result = new LinkedList<>();
for (Map.Entry<String, Integer> entry : entries) {
  result.add(entry.getKey());
}

0
import java.util. TreeSet;

import java.util.Set; import java.util.concurrent.ConcurrentHashMap;

public class Test {

import java.util.Set; import java.util.concurrent.ConcurrentHashMap;

公共类测试{

public static void main(String[] args){
    ConcurrentHashMap< String, Integer> map = new ConcurrentHashMap<String , Integer>();
    map.put("Fish", 1);
    map.put("Bird", 100);
    map.put("Reptile", 2);
    map.put("Mammal", 10);
    TreeSet <Integer> sortedList = new TreeSet <Integer>(map.values());
    for(Integer i :sortedList){
        System.out.println(i);
    }
}

}


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接