检索按值排序的地图中条目周围的固定数量的条目

POJO即。 Entry.java表示排行榜中的条目。 排名是排行榜中的位置,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 leaderBoardUserEntryMap; public void submitScore(String uid, int score) { Entry newEntry = new Entry(uid, score); leaderBoardUserEntryMap.put(uid, newEntry); } public List 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()应该返回

最多两个分数比用户(在排行榜中位于用户之上的用户)更大的分数,用户自己的条目以及紧接在排行榜中用户之后的最多两个条目

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

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

@nullpointer提供的以下片段可以解决这个问题,但我有一些观点

 List 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()会导致问题吗?

    List entries = leaderBoardUserEntryMap.entrySet()。parallelStream()。sorted(Map.Entry.comparingByValue(Comparator.comparing(Entry :: getScore,Integer :: compare).reversed()))。parallel()。 地图(Map.Entry的::的getValue).collect(Collectors.toList());

Stream#limit将帮助您限制在您创建的反向列表中查找前N (5)个用户,并且您可以使用这些值映射List>并最终从中收集List

 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的用例

假设有100个用户,正在搜索的用户是93.列表应该返回91,92,93,94,95。此解决方案将返回1,2,3,4,5

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

 List 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

indexOfnewEntry和+ – 2可以导致IndexOutOfBoundsException,防止它看起来有点单调乏味,这里有什么最佳方式吗?

由于条目的index可能在分数上变化,并且子subList访问还进一步依赖于在其之前/之后所需的输出的数量。 保护应该是比任何其他保护更好的选择。 还可以考虑的是customSubList实现,它可以在内部检查您的集合类型。 如何使用subList()以最高投票答案解释这一点。 我特别喜欢这个:

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

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

除非执行的任何synchronized块可能会更改并对流进行并发更新 ,否则不会导致任何问题。

但您应该知道何时使用并行流 – 我是否应该尽可能使用并行流?