java - 在按值排序的 map 中的条目周围检索固定数量的条目

标签 java collections java-8 java-stream

POJO 即。入口.java 代表排行榜中的条目。 Position为排行榜中的位置,1为得分最高的用户

public class Entry {

    private String uid;
    private int score;
    private int position;

@Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + score;
        result = prime * result + ((uid == null) ? 0 : uid.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;

        if (!(obj instanceof Entry))
            return false;

        Entry other = (Entry) obj;
        if (score != other.score)
            return false;
        if (uid == null) {
            if (other.uid != null)
                return false;
        } else if (!uid.equals(other.uid))
            return false;
        return true;
    }

    @Override
    public String toString() {
        return "Entry [uid=" + uid + ", score=" + score + ", position=" + position + "]";
    }
}

这些条目存储在类中的 Map 中,如下所示:

public class GameDefault {

Map<String, Entry> leaderBoardUserEntryMap;

public void submitScore(String uid, int score) {

        Entry newEntry = new Entry(uid, score);
        leaderBoardUserEntryMap.put(uid, newEntry);
    }

public List<Entry> getLeaderBoard(String uid) {

    /* Option-3 : A Map of uid-Entry */
    leaderBoardUserEntryMap.entrySet().stream().sorted(Map.Entry.comparingByValue(Comparator.comparing(Entry::getScore, Integer::compare).reversed()))
                .filter(/*What to put here*/);

        return null;
    }
}

getLeaderBoard() 方法应该返回

max two entries that have larger score than the user (the users that are immediately above the user in the leaderboard), the user’s own entry and max two entries that are immediately after the user in the leaderboard

.

我无法弄清楚用于返回恰好 5 个条目的谓词,包括正在搜索的条目。另一个方面是性能,因为排行榜可以有数十万个条目。

************编辑-1**********

@nullpointer 提供的以下代码片段可以解决问题,但我有一些想法

List<GameEntry> selectedEntries =  leaderBoardUserEntryMap.entrySet().stream()
            .sorted(Map.Entry.comparingByValue(Comparator.comparing(GameEntry::getScore, Integer::compare)
                    .reversed())).map(Map.Entry::getValue).collect(Collectors.toList());

int indexOfnewEntry = selectedEntries.indexOf(leaderBoardUserEntryMap.get(uid));
return  selectedEntries.subList(indexOfnewEntry-2,indexOfnewEntry+2);

注意:leaderBoardUserEntryMap 可以有数百万个条目

  • indexOfnewEntry 和 +- 2 会导致 IndexOutOfBoundsException,防止它似乎有点乏味,这里有什么优化的方法吗?

  • 使用 parallelStream() 会导致问题吗?

    列表条目 = leaderBoardUserEntryMap.entrySet().parallelStream().sorted(Map.Entry.comparingByValue(Comparator.comparing(Entry::getScore, Integer::compare).reversed())).parallel()。 map(Map.Entry::getValue).collect(Collectors.toList());

最佳答案

Stream#limit 将帮助您限制查找顶部 N (5) 您创建的反向列表中的用户,您可以进一步映射 List> 使用值并收集 List<Entry>最后从它作为:

return leaderBoardUserEntryMap.entrySet().stream()
            .sorted(Map.Entry.comparingByValue(Comparator.comparing(Entry::getScore, Integer::compare).reversed()))
            .limit(5).map(Map.Entry::getValue).collect(Collectors.toList());

编辑:感谢@Yogesh 的用例

say there are 100 users, and the user that is being searched is at 93. List should return 91, 92, 93, 94, 95. This solution will return 1, 2, 3, 4, 5

因为用例是有一个 subList 在当前条目周围,这可以修改为:

List<GameEntry> selectedEntries =  leaderBoardUserEntryMap.entrySet().stream()
            .sorted(Map.Entry.comparingByValue(Comparator.comparing(GameEntry::getScore, Integer::compare)
                    .reversed())).map(Map.Entry::getValue).collect(Collectors.toList());

int indexOfnewEntry = selectedEntries.indexOf(leaderBoardUserEntryMap.get(uid));
return  selectedEntries.subList(indexOfnewEntry-2,indexOfnewEntry+2);

编辑 2:

The indexOfnewEntry and +- 2 can cause IndexOutOfBoundsException, guarding against it seems a bit tedious, any optimal ways here?

index条目的分数可能会有所不同,并且 subList进一步访问还依赖于它之前/之后所需的输出数量。守卫应该是比任何其他更好的选择。同样可以考虑的是 customSubList可以在内部检查您的集合类型的实现。 How to use subList()用投票最多的答案解释这一点。不过我特别喜欢这个:

dataList.subList(Math.max(0, first), Math.min(dataList.size(), last) );

Will using parallelStream() cause problems?

除非有任何synchronized执行的 block 可能会改变流并并发更新它不会导致任何问题。

但是你应该知道什么时候使用并行流 - Should I always use a parallel stream when possible?

关于java - 在按值排序的 map 中的条目周围检索固定数量的条目,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46172817/

相关文章:

python - Python中有类型收集工具吗?

java - 如何在 Swing 中显示随机图像

java - tableModel.addRow() 未在 JTable 中显示任何内容,但行对象具有值

java - Java 中的条件委托(delegate)

java - 将 Clojure 函数作为 java.util.Function 传递

java - 不等于符号(java)

java - 在 HashMap 中选择性地随机生成键

java - Windows 10 企业版 IntelliJ IDEA 中的 JDK 路径

java - Spring @Value 与 arraylist 分割并获取第一个值

Java HttpURLConnection 神秘死亡