Getting Map.Entry with highest integer value

Discussion in 'Plugin Development' started by joeygallegos, Dec 13, 2014.

Thread Status:
Not open for further replies.
  1. Offline

    joeygallegos

    I have a Map setup with UUID as Key and Integer as Value and at the end of a round, I try to get the Map.Entry with the highest integer value possibly using a loop? Other methods I've tried have failed.

    Code:
    private Map.Entry getWinnerStat(Map<UUID, Integer> set) {
            Map.Entry<UUID, Integer> top = null;
            for (Map.Entry<UUID, Integer> entry : set.entrySet()) {
                // TODO: Logic?
            }
            return null;
        }
     
  2. Offline

    adam753

    Code:
    if(top == null || entry.getValue() > top.getValue())
        top = entry;
    (And don't forget to return top)
     
  3. Offline

    joeygallegos

    @adam753 I already have been on that stackoverflow thread and tried out the code myself, strange enough it just weirdly returns a random Entry.
     
  4. Offline

    adam753

    @joeygallegos
    I didn't get that from google, I wrote it myself, it seemed very obvious. Strange that it's not working, can you show a sample input and output?
     
  5. Offline

    joeygallegos

    Last edited: Dec 13, 2014
  6. Offline

    adam753

    @joeygallegos
    How is that condition always true? That's weird... Maybe some brackets are in order?
    Code:
    if((top == null) || (entry.getValue() > top.getValue()))
     
  7. Offline

    joeygallegos

    @adam753 that does exactly the same thing unfortunately.
     
  8. Offline

    adam753

    @joeygallegos
    That's really weird.
    Just out of interest, this is how I would have written the method:
    Code:java
    1. private UUID getWinnerStat(Map<UUID, Integer> map) {
    2. UUID topPlayer = null;
    3. int topScore = -99999; //Very low number
    4.  
    5. for(UUID id : map.keySet()) {
    6. if(map.get(id) > topScore) {
    7. topScore = map.get(id);
    8. topPlayer = id;
    9. }
    10. }
    11.  
    12. return topPlayer;
    13. }

    So I guess try that if you're in the mood for tearing it down and trying again.
     
  9. Offline

    drpk

    @joeygallegos judging from your previous screenshot, you never assign a value to top. Also, returning null?
     
  10. Offline

    fireblast709

    @joeygallegos post your attempt. @adam753 's first post contains correct code, so I'm guessing you must've added something to break it.
     
  11. Offline

    Dragonphase

    @joeygallegos

    You could use a comparator:

    ValueComparator.java

    Code:
    import java.util.Comparator;
    import java.util.Map;
    
    public class ValueComparator<K> implements Comparator<K> {
    
        private Map<K, Integer> map;
    
        private ValueComparator() {
            super();
        }
    
        public ValueComparator(Map<K, Integer> map) {
            this();
            this.map = map;
        }
    
        public int compare(K o1, K o2) {
            return map.get(o1) >= map.get(o2) ? -1 : 1;
        }
    }
    Utils.java

    Code:
    import java.util.*;
    
    public final class Utils {
    
        private Utils() {}
    
        public static Map<UUID, Integer> sortByValue(Map<UUID, Integer> map) {
            ValueComparator<UUID> comparator = new ValueComparator<UUID>(map);
            Map<UUID, Integer> sortedMap = new TreeMap<UUID, Integer>(comparator);
            sortedMap.putAll(map);
            return sortedMap;
        }
    }
    This sorts the map from highest to lowest.

    Usage:

    Code:
    Map<UUID, Integer> sortedMap = (TreeMap<UUID, Integer>) Utils.sortByValue(map);
    Map.Entry<UUID, Integer> winner = sortedMap.firstEntry();
     
    Last edited: Dec 13, 2014
  12. Offline

    joeygallegos

  13. Offline

    fireblast709

    @joeygallegos the interesting part is that it works completely fine for me.
    Code:java
    1.  
    2. Map<String, Integer> map = new HashMap<String, Integer>();
    3. map.put("a", 7);
    4. map.put("b", 10);
    5. map.put("c", 5);
    6. Map.Entry<String, Integer> top = null;
    7. for(Map.Entry<String, Integer> entry : map.entrySet())
    8. {
    9. if(top == null || entry.getValue() > top.getValue())
    10. top = entry;
    11. }
    12. System.out.println("Top is "+(top == null ? "null" : top.getKey()));
    This prints 'b'.
     
  14. Offline

    joeygallegos

    @fireblast709 this still gives the same result posted from console as earlier. I know it should work, but isn't. Maybe because I'm storing UUID's as key? But I don't see how that would affect it in anyway.
     
  15. Offline

    Avygeil

    @joeygallegos or just use Java 8 ;)
    Code:
    scores.entrySet().stream().max((a, b) -> a.getValue() >= b.getValue() ? 1 : -1).get();
    Either way, all other snippets should work, maybe print the content of your Map to debug?
     
  16. Offline

    Dragonphase

    @Avygeil

    Lambdas can be very useful, but when you consider the fact that not all servers will be running Java 8, it isn't really a valid solution.

    As for @fireblast709 's solution not working for @joeygallegos , it's pretty strange. I can't see it being caused by the fact that you're using UUID as a key. Perhaps you did something wrong?
     
  17. Offline

    Avygeil

    @Dragonphase I was just pointing out how to reduce your code down to one line. :) It doesn't mean it's not a valid solution, actually if more people did this more admins and providers would have to move to 8. ;)
     
  18. @Avygeil Or less people would use your plugin because they get an error they can't be bothered to ask about ;)
     
    Avygeil likes this.
  19. Offline

    Avygeil

    @AdamQpzm You make a good point, but I think they shouldn't install plugins if they can't read a "Requirements" section in the first place. :) Now my opinion is biased because I never published my plugins. But I'll leave it here since it's getting offtopic and we don't even know OP's JDK version. :p
     
    Last edited: Dec 15, 2014
    AdamQpzm likes this.
  20. Offline

    joeygallegos

    This is the code I'm using to get the Map.Entry at the end of the round. Don't understand how it could be wrong.
    Code:
    public class Demo {
    
       
        public void doTick() {
    
            if (state == 0) {
                game.setCurrentState(GameState.getState("Waiting"));
            }
           
            // -SNIP -
            // IN-GAME
            else if (state == 3) {
    
                // TIME MESSAGE
                if (ticks > 0 && ticks % 15 == 0 ||
                        ticks > 0 && ticks <= 10) {
    
                    if (Core.getState() == RoundState.COUNTDOWN) {
                        message(MessageType.INFO, "Next round starts in §b" + MsgUtil.calculateTime(ticks, false) + "§7!");
                    } else if (Core.getState() == RoundState.INPROGRESS) {
                        message(MessageType.INFO, "Round §b" + round + " §7ends in §b" + MsgUtil.calculateTime(ticks, false) + "§7!");
                    }
                } else if (ticks == 0) {
    
                    if (Core.getState() == RoundState.COUNTDOWN) {
    
                        // TODO: Start next round!
                        Core.setState(RoundState.INPROGRESS);
                        setTicks(roundTime);
    
                        message(MessageType.INFO, " ");
                        message(MessageType.INFO, "§6§lRound " + round + " has started! ");
                        message(MessageType.INFO, " ");
                    } else if (Core.getState() == RoundState.INPROGRESS) {
    
                        Map.Entry<UUID, Integer> winner = getWinnerStat(FlowerBox.getFlowerPot());
                        ClarityPlayer player = PlayerManager.getPlayer(winner.getKey());
    
                        if (winner != null) {
                            message(MessageType.DETAILS, " ");
                            message(MessageType.DETAILS, "Round winner is §b" + player.getName() + " §7!");
                            message(MessageType.DETAILS, " ");
    
                            logWinner(winner);
    
                            int reward = winner.getValue() / 4;
                            if (reward > 0) Currency.awardCredits(player, reward, true);
    
                            FlowerBox.printValues();
                            FlowerBox.resetScores();
                        } else {
                            message(MessageType.DETAILS, " ");
                            message(MessageType.DETAILS, "There is no winner this round!");
                            message(MessageType.DETAILS, " ");
    
                            FlowerBox.printValues();
                            FlowerBox.resetScores();
                        }
    
                        Core.setState(RoundState.FINISHED);
                    } else if (Core.getState() == RoundState.FINISHED) {
                        if (round == maxRound) {
    
                            setTicks(10);
                            changeState(4);
                        } else if (round < maxRound) {
                            // TODO: If not round 3, then change state and add ticks to counter
                            round++;
                            Core.setState(RoundState.COUNTDOWN);
                            setTicks(20);
                        }
                    }
    
                }
            }
            // -SNIP-
        }
       
        private Map.Entry getWinnerStat(Map<UUID, Integer> set) {
            Map.Entry<UUID, Integer> top = null;
            for (Map.Entry<UUID, Integer> entry : set.entrySet()) {
                if (top == null || entry.getValue() > top.getValue()) top = entry;
                return top;
            }
            return null;
        }
    
        private void logWinner(Map.Entry<UUID, Integer> entry) {
            com.claritygalaxy.ServerAPI.Core.getPlugin().getLogger().info(PlayerManager.getPlayer(entry.getKey()).getName() + " won with " + entry.getValue());
        }
    }
     
  21. @joeygallegos The problem is that you return the top result after the first for loop iteration. You want the return statement outside the for loop (where the return null currently is)
     
Thread Status:
Not open for further replies.

Share This Page