按排序顺序存储条目并检索条目周围的条目

我正在尝试模拟一个游戏板,其中多个玩家可以提交他们的游戏分数。

POJO即。 Entry.java表示排行榜中的条目。 请注意重写的equals()方法

排名是排行榜中的位置,1是得分最高的用户

public class EntryTreeMapOption { private String uid; private int score; private int position; public EntryTreeMapOption(String uid, int score) { this.uid = uid; this.score = score; } public EntryTreeMapOption() { } public String getUid() { return uid; } public void setUid(String uid) { this.uid = uid; } public int getScore() { return score; } public void setScore(int score) { this.score = score; } public int getPosition() { return position; } public void setPosition(int position) { this.position = position; } @Override public int hashCode() { final int prime = 31; int result = 1; 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; EntryTreeMapOption other = (EntryTreeMapOption) obj; 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 + "]"; }} 

GameBoard类有几种方法:

  • submitScore(String uid,int score)每个玩家都会调用此方法将其分数提交给游戏板。 每个玩家/用户只有一个条目,因此,如果玩家多次调用此方法,则会存储他的最新分数
  • getLeaderBoard(String uid)

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

例如:

 The leader board is : Entry [uid=user1, score=14, position=1] Entry [uid=user2, score=8, position=2] Entry [uid=user3, score=7, position=3] Entry [uid=user4, score=7, position=3] Entry [uid=user5, score=4, position=4] Entry [uid=user6, score=3, position=5] Entry [uid=user7, score=3, position=5] Entry [uid=user8, score=1, position=6] For user5, entries returned should be : Entry [uid=user3, score=7, position=3] Entry [uid=user4, score=7, position=3] Entry [uid=user5, score=4, position=4] Entry [uid=user6, score=3, position=5] Entry [uid=user7, score=3, position=5] For user4, entries returned should be : Entry [uid=user1, score=14, position=1] Entry [uid=user2, score=8, position=2] Entry [uid=user4, score=7, position=3] Entry [uid=user5, score=4, position=4] Entry [uid=user6, score=3, position=5] For user6, entries returned should be : Entry [uid=user4, score=7, position=3] Entry [uid=user5, score=4, position=4] Entry [uid=user6, score=3, position=5] Entry [uid=user8, score=1, position=6] For user7, entries returned should be : Entry [uid=user4, score=7, position=3] Entry [uid=user5, score=4, position=4] Entry [uid=user7, score=3, position=5] Entry [uid=user8, score=1, position=6] 

我最初的方法是使用TreeMap, 这里讨论替代方案。

 public class GameDefault2 { private TreeMap leaderBoardEntryUserMap; { leaderBoardEntryUserMap = new TreeMap(Comparator.comparingInt(EntryTreeMapOption::getScore).reversed() .thenComparing(EntryTreeMapOption::getUid)); } @Override public void submitScore(String uid, int score) { EntryMapOption newEntry = new EntryMapOption(uid, score); leaderBoardEntryUserMap.put(newEntry, uid); } @Override public List getLeaderBoard(String uid) { System.out.println("---------Current leader board---------"); leaderBoardEntryUserMap.keySet().forEach(System.out::println); List userEntryList = leaderBoardEntryUserMap.entrySet().stream() .filter(entry -> uid.equalsIgnoreCase(entry.getKey().getUid())).map(Map.Entry::getKey) .collect(Collectors.toList()); if (userEntryList == null || userEntryList.isEmpty()) return Collections.emptyList(); // Incomplete and error prone EntryMapOption userEntry = userEntryList.get(0); List entriesOptionTwo = new ArrayList(); entriesOptionTwo.add(leaderBoardEntryUserMap.higherKey(userEntry)); entriesOptionTwo.add(userEntry); entriesOptionTwo.add(leaderBoardEntryUserMap.lowerKey(userEntry)); return entriesOptionTwo; } } 

以上代码的问题:

  • 何时(理想情况下,在submitScore()期间)以及如何计算“位置”。 虽然它用于键,但我想知道Map.compute()是否可以以任何方式提供帮助!
  • 检查下面的代码’// Incomplete and error prone’注释虽然’higherKey()’和’lowerKey()’很方便,但我不确定如何使用它们在特定条目下方和上方选择固定数量的条目

*****编辑-1 ****** @ Holger的修复解决了以下问题

  • 我无法弄清楚如何修复equals()和compare()之间的不一致。 这导致缺少条目

地图的潜在问题

您的equals方法基于ID,但您的比较方法基于得分,这将导致JavaDoc出现问题。

请注意,如果此有序映射要正确实现Map接口,则树映射维护的顺序(如任何有序映射,以及是否提供显式比较器)必须与equals一致。 (请参阅Comparable或Comparator以获得与equals一致的精确定义。)这是因为Map接口是根据equals操作定义的,但是有序映射使用compareTo(或compare)方法执行所有键比较,因此两个从排序映射的角度来看,通过此方法被视为相等的键是相等的。 即使排序与equals不一致,也可以很好地定义有序映射的行为。 它只是没有遵守Map接口的一般合同。

问题是比较方法将在错误的方向上进行搜索,因为它在不同的属性上进行排序。

在你的情况下,这可能不是一个问题,虽然你可能有2个相同的对象没有相同的分数,导致未来的问题。

使用TreeMap的潜在问题

在项目位于树中时更改分数也可能会导致问题,因此您可能必须在每次分数更改时删除该项目,然后重新添加它们。

工作代码

这个过程的一个例子就是这个

 import java.util.Comparator; import java.util.TreeMap; public class Test { static class Example { final int id; final int score; Example(int id, int score) { this.id = id; this.score = score; } @Override public boolean equals(Object obj) { if (!(obj instanceof Example)) { return false; } final Example other = (Example) obj; return other.id == id; } @Override public int hashCode() { return id; } public int getId() { return id; } @Override public String toString() { return id + " scored " + score; } public int getScore() { return score; } } public static void main(final String... args) { Example a = new Example(1, 10); Example b = new Example(2, 30); Example c = new Example(3, 1); Example d = new Example(4, 10); TreeMap x = new TreeMap(Comparator.comparingInt(Example::getScore).thenComparing(Example::getId)); x.put(a, a.getScore()); x.put(b, b.getScore()); x.put(c, c.getScore()); x.put(d, d.getScore()); final Example h2 = x.higherKey(a); final Example h1 = h2 == null ? null : x.higherKey(h2); final Example l1 = x.lowerKey(a); final Example l2 = l1 == null ? null : x.lowerKey(l1); System.out.println(h1); System.out.println(h2); System.out.println(a); System.out.println(l1); System.out.println(l2); } }