Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/348.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 什么';这是获取地图中前N个元素的最佳方法<;字符串,双>;基于他们的价值观?_Java_Functional Programming - Fatal编程技术网

Java 什么';这是获取地图中前N个元素的最佳方法<;字符串,双>;基于他们的价值观?

Java 什么';这是获取地图中前N个元素的最佳方法<;字符串,双>;基于他们的价值观?,java,functional-programming,Java,Functional Programming,例如,如果我有一个由{a',0.0},{B',3.14},{C',3.14},{D',8.8},{E',2.1},{F',1.01}组成的映射,最上面的3个键将是{D”,“B”,“C} 我知道实现这一点的过程性方法,但在Java8中是否有更智能/功能性的方法 编辑:请注意,我们可以将映射的每个元素放入大小为N的优先级队列中,因此时间复杂度应为Mlog(N),比排序所有M个元素(即Mlog(M))要快 编辑2:根据要求,这是我得到的: public static void main(String

例如,如果我有一个由
{a',0.0},{B',3.14},{C',3.14},{D',8.8},{E',2.1},{F',1.01}
组成的映射,最上面的3个键将是
{D”,“B”,“C}

我知道实现这一点的过程性方法,但在Java8中是否有更智能/功能性的方法

编辑:请注意,我们可以将映射的每个元素放入大小为N的优先级队列中,因此时间复杂度应为Mlog(N),比排序所有M个元素(即Mlog(M))要快

编辑2:根据要求,这是我得到的:

 public static void main(String args[]) {
    final Map<String, Double> map = new HashMap<String, Double>() {{
      put("A", 0.0);
      put("B", 3.14);
      put("C", 3.14);
      put("D", 8.8);
      put("E", 2.1);
      put("F", 1.01);
    }};
    System.out.println("answer= " + getTopN(map, 3).toString());
  }

  static List<String> getTopN(final Map<String, Double> map, int n) {
    // Creating priority queue with limit size n
    PriorityQueue<Entry<String, Double>> pq = new PriorityQueue<>(n, Entry.comparingByValue());
    for (Entry<String, Double> entry : map.entrySet()) {
      pq.add(entry);
      if (pq.size() > n) {
        pq.poll();
      }
    }
    Stack<String> stack = new Stack<>();
    while (!pq.isEmpty()) {
      stack.add(pq.poll().getKey());
    }
    final ArrayList<String> answer = new ArrayList<>();
    while (!stack.isEmpty() && n-- > 0) {
      answer.add(stack.pop());
    }
    return answer;
  }
publicstaticvoidmain(字符串参数[]){
final Map=new HashMap(){{
put(“A”,0.0);
付诸表决(“B”,3.14);
付诸表决(“C”,3.14);
付诸表决(“D”,8.8);
付诸表决(“E”,2.1);
付诸表决(“F”,1.01);
}};
System.out.println(“answer=“+getTopN(map,3.toString());
}
静态列表getTopN(最终映射,int n){
//正在创建限制大小为n的优先级队列
PriorityQueue pq=新的PriorityQueue(n,Entry.comparingByValue());
for(条目:map.entrySet()){
pq.添加(条目);
如果(pq.size()>n){
pq.poll();
}
}
堆栈=新堆栈();
而(!pq.isEmpty()){
stack.add(pq.poll().getKey());
}
最终ArrayList答案=新建ArrayList();
而(!stack.isEmpty()&&n-->0){
add(stack.pop());
}
返回答案;
}

这里有一种按输入值使用反向双比较器的方法:

Map<String, Double> map = new HashMap<>();
map.put("A", 0.0);
map.put("B", 3.14);
map.put("C", 3.14);
map.put("D", 8.8);
map.put("E", 2.1);
map.put("F", 1.01);

List<String> topKeys = map.entrySet().stream()
        .sorted(Comparator.<Entry<String, Double>>comparingDouble(Entry::getValue)
                 .reversed())
        .limit(3) //limit to 3
        .map(Entry::getKey)
        .collect(Collectors.toList());
Map Map=newhashmap();
地图放置(“A”,0.0);
地图.put(“B”,3.14);
地图放置(“C”,3.14);
地图.put(“D”,8.8);
地图.付诸表决(“E”,2.1);
地图放置(“F”,1.01);
List topKeys=map.entrySet().stream()
.sorted(Comparator.comparingDouble(条目::getValue)
.reversed())
.限制(3)//限制为3
.map(条目::getKey)
.collect(Collectors.toList());

返回的列表包含
[D,B,C]

您的代码可以通过使用(而不是
PriorityQueue
Stack
)来改进:

静态列表getTopN(Map-Map,int-n){
树集topN=新树集(
Map.Entry.comparingByValue()的
.reversed()//先按值降序,然后按键
.thenComparing(Map.Entry::getKey));//允许具有重复值的条目
map.entrySet().forEach(e->{
topN.添加(e);
如果(topN.size()>n)topN.pollLast();
});
返回topN.stream()
.map(map.Entry::getKey)
.collect(Collectors.toList());
}
请注意,我使用的是一个比较器,它按值降序,然后按键对条目的
TreeSet
进行排序。这是为了使集合能够包含具有相等值的条目


该方法相当于
PriorityQueue.poll()
方法。

可能的重复:。。。我认为您只是在寻找一种Java8方法来根据值对映射进行排序/迭代。上面链接中的几个答案向您展示了如何做到这一点。可能重复的答案并不重复。因为要对整个映射大小为M的队列进行排序,时间复杂度是M log(M),而要得到前N名,时间复杂度是M log(N)。Java中的优先级队列无法迭代。你能做的最好的事情就是在
O(1)
中查看最小/最大元素,然后在
O(logN)
中弹出/拉取最小/最大元素。这对你的案子来说够了吗?@Federicoperaltachaffner我已经编辑了我的帖子,把我所拥有的都包括进去了。太难看了吗?我真的想不出一个使它优雅的方法。看起来很漂亮!我们可以在不排序整个地图的情况下进行功能性操作吗?就像使用优先级队列一样,只需要top N。@ijklr您可以将其替换为成对对象的集合。。。对吗?不确定替换是什么意思,你能详细说明这个问题吗?@ijklr不是
map.entrySet().stream()
,而是使用类似
Arrays.asList(成对的(“A”,0.0),成对的(“B”,3.14)….stream()
。我指的是commons lang的那对class@ernest_k很抱歉,您的代码实际上有效,我只是解释了错误的结果。(我在一个更复杂的测试用例上测试,弄糊涂了……)我运行了我的示例,它有效。intellij IDE说topN的类型是TreeSethow我应该提示编译器吗?这是错误消息:error:(68,54)java:不兼容类型:无法推断java.util.TreeSet的类型参数原因:推断变量E具有不兼容的边界等式约束:java.util.Map.Entry上限:java.util.Map.Entry,java.lang。Object@ijklr已经修复了编译错误,请看是的,它可以工作。我做了一些基准测试,它的性能与我所做的类似。也许还有一些额外的改进空间(但不确定是否会有一些性能提升)。。。对于
topN
,您可以使用
TreeMap
,而不是使用
TreeSet
。然后,只需将值作为
集合
,或者
新的ArrayList(topN.values())
返回(如果您确实需要列表)。
static List<String> getTopN(Map<String, Double> map, int n) {

    TreeSet<Map.Entry<String, Double>> topN = new TreeSet<>(
        Map.Entry.<String, Double>comparingByValue()
            .reversed()                         // by value descending, then by key
            .thenComparing(Map.Entry::getKey)); // to allow entries with repeated values

    map.entrySet().forEach(e -> {
      topN.add(e);
      if (topN.size() > n) topN.pollLast();
    });

    return topN.stream()
        .map(Map.Entry::getKey)
        .collect(Collectors.toList());
}