在SortedMap(TreeMap)中使用“position”更新POJO属性 [英] Update a POJO property with 'position' in a SortedMap(TreeMap)

查看:126
本文介绍了在SortedMap(TreeMap)中使用“position”更新POJO属性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am trying to simulate a game board where multiple players can submit their game scores.

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

The POJO viz. Entry.java represents an entry in the leaderboard. Note the overriden equals() method.


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

Position is the position in the leaderboard, 1 being the user with the highest score



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 + "]";
}}

我使用TreeMap根据分数存储条目,它们是自动排序的

I am using a TreeMap to store the entries, based on the score, they are sorted automatically

public class GameDefault2 {

    private TreeMap<EntryMapOption, String> 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<EntryMapOption> getLeaderBoard(String uid) {

        List<EntryMapOption> userEntryList = .....
        .....
        .....

        return entriesOptionTwo;

    }

}

我如何设置条目的位置字段?例如:以下是根据分数排序的条目,如何获得相应的索引/位置并在条目中设置?

How do I set the 'position' field of an Entry ? e.g: Below are entries sorted as per the scores, how do I get the corresponding 'index/position' and set it in the entry ?

Entry [uid=user1, score=14, position=0]
Entry [uid=user2, score=8, position=0]
Entry [uid=user3, score=7, position=0]
Entry [uid=user4, score=7, position=0]
Entry [uid=user5, score=4, position=0]
Entry [uid=user6, score=3, position=0]
Entry [uid=user7, score=3, position=0]
Entry [uid=user8, score=1, position=0]

现在,user1条目的position = 1,user2条目的position = 2,依此类推。

Now, user1 entry should have position=1, user2 entry should have position=2 and so on.

推荐答案

或许,您最好使用已排序的列表

Perhaps, you’re better off with a sorted List.

考虑

public class RankList<T> extends AbstractCollection<T> {

    private final Comparator<T> order;
    private final List<T> contents;

    public RankList(Comparator<T> order) {
        this.order = Objects.requireNonNull(order);
        contents = new ArrayList<>();
    }
    public RankList(Comparator<T> order, List<? extends T> initialContents) {
        this.order = Objects.requireNonNull(order);
        contents = new ArrayList<>(initialContents);
        contents.sort(order);
    }

    @Override
    public boolean add(T e) {
        int index = Collections.binarySearch(contents, e, order);
        if(index>=0) return false;
        contents.add(~index, e);
        return true;
    }

    public int addAndGetIndex(T e) {
        int index = Collections.binarySearch(contents, e, order);
        if(index>=0) throw new IllegalStateException("duplicate element");
        index = ~index;
        contents.add(index, e);
        return index;
    }

    @Override
    public boolean remove(Object o) {
        T t = (T)o;
        int index = Collections.binarySearch(contents, t, order);
        if(index<0) return false;
        contents.remove(index);
        return true;
    }

    @Override
    public boolean contains(Object o) {
        T t = (T)o;
        return Collections.binarySearch(contents, t, order)>=0;
    }

    public int indexOf(T element) {
        int ix = Collections.binarySearch(contents, element, order);
        return ix<0? -1: ix;
    }

    public List<T> asList() {
        return Collections.unmodifiableList(contents);
    }

    @Override
    public Iterator<T> iterator() {
        return contents.iterator();
    }

    @Override
    public int size() {
        return contents.size();
    }
}

通过确保列表始终排序,您可以利用查找和插入操作中的排序特性,因此您将具有相同的 O(log n)时间复杂度 TreeMap ,由于扁平阵列存储,对于大量元素,所需空间可能更小。在 RankList 这样的另一个类中包装 List 有助于确保在修改时排序的属性不会被意外失效列表

By ensuring that the list is always sorted, you can exploit the sorted nature in lookup and insertion operations, so you’ll have the same O(log n) time complexity as TreeMap, the required space might be even less for larger number of elements due to the flat array storage. Wrapping the List in another class like RankList helps ensuring that the sorted property can’t get invalidated by accident when modifying the List.

在更改其排序属性时,仍然需要删除并重新插入元素,但它仍然是直接的,例如

It’s still required to remove and re-insert an element when changing its ordering property, but it’s still straight-forward, e.g.

RankList<EntryOption> rankList=new RankList<>(
    Comparator.comparingInt(EntryOption::getScore).reversed()
              .thenComparing(EntryOption::getUid));
ThreadLocalRandom r = ThreadLocalRandom.current();
for(int id=1; id<100; id++)
    rankList.add(new EntryOption(String.valueOf(id), r.nextInt(100)));

EntryOption justAnother = new EntryOption("101", r.nextInt(100));
int pos = rankList.addAndGetIndex(justAnother);
int rangeStart = Math.max(0, pos-2), rangeEnd=Math.min(rankList.size(), rangeStart+5);

System.out.println("entries around "+justAnother);
rankList.asList().subList(rangeStart, rangeEnd)
        .forEach(System.out::println);

System.out.println("update score of "+justAnother);

rankList.remove(justAnother);
justAnother.score+=20;
rankList.add(justAnother);

System.out.println("entries around "+justAnother);
pos = rankList.indexOf(justAnother);
rangeStart = Math.max(0, pos-2); rangeEnd=Math.min(rankList.size(), rangeStart+5);
rankList.asList().subList(rangeStart, rangeEnd)
        .forEach(System.out::println);

但是,当您要更新所有元素时,执行批量处理可能更有效之后更新并实例化一个新的 RankList ...

When you’re going to update all elements, however, it might be more efficient to perform the bulk update and instantiate a new RankList afterwards…

或添加类似

public void updateAll(Consumer<? super T> updateElementAction) {
    contents.forEach(updateElementAction);
    contents.sort(order);
}

RankList if您可以将更新操作表示为 Consumer ,让列表暂时未排序,然后使用单个 sort 操作进行验证。

to RankList if you can express the update action as Consumer, letting the list temporarily go unsorted and validate with a single sort operation afterwards.

这篇关于在SortedMap(TreeMap)中使用“position”更新POJO属性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆