0

I'm using a HashMap<String,Integer> for a sort of timed Voting system. Where the string is the name of the object, and the integer is the amount of votes that object has. What I'm trying to do, is sort the integer descending, and if their is a tie, I'd like to choose whichever did not previously win the vote (if either of them did)

I tried using a TreeMap, but it doesn't seem to do what I want, since it sorts based on the value of the key, while I need the value sorted. Also doesn't work as some times two objects could both have the same number of votes.

ROMANIA_engineer
  • 54,432
  • 29
  • 203
  • 199
ctooley17
  • 99
  • 10
  • 2
    can you put example of your code, – Maytham Fahmi Apr 16 '17 at 00:30
  • You can use a simple sorting algorythm that you designfor tis instance but if you put some of your code it would be helpful – Gürtuğ Güngör Apr 16 '17 at 00:32
  • @maytham-ɯɐɥʇʎɐɯ I don't believe this is a duplicate, because of the tie-breaker requirement – fps Apr 16 '17 at 00:57
  • 1
    Could you please clarify how is the tie to be broken exactly? i.e. if there are 3 votes for Paul and 2 votes for Ann, and Ann is voted, then Ann needs to appear before Paul in the ordering, because Paul is the one who has previously wan the vote. Is this correct? What if there are more people with 3 votes (other than Paul) when Ann (who has 2 votes) is voted (and Paul is the one who was voted previously)? Please clarify all this to receive a good answer. – fps Apr 16 '17 at 01:16
  • 1
    Seems you can not do it just sorting Integer. You need to move the information to an object with Integer and other flag. Then, at the sorting algorithm will need to use this flag to complete your logic. – Walter Palladino Apr 16 '17 at 02:01
  • Possible duplicate of [Sort a Map by values (Java)](http://stackoverflow.com/questions/109383/sort-a-mapkey-value-by-values-java) – Ferrybig Apr 16 '17 at 21:33
  • @Ferrybig No, it's not a duplicate because of the tie-break thing – fps Apr 17 '17 at 17:19
  • 1
    Duplicate of [Bukkit Map Voting](http://stackoverflow.com/questions/41889903/bukkit-map-voting). See this [answer](http://stackoverflow.com/a/41914372/3304238) for a solution. – Frelling Apr 18 '17 at 00:11

2 Answers2

0

Taken from here, here is how you can sort a Map by its values (in descending order) with JDK 8:

public static <K, V extends Comparable<? super V>> Map<K, V> sortByValue(Map<K, V> map) {
    return map.entrySet().stream().sorted(Map.Entry.comparingByValue(Collections.reverseOrder())).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new));
}

Example:

Map<String, Integer> votes = new HashMap<>();

votes.put("A", 5);
votes.put("B", 17);
votes.put("C", 1);

System.out.println(votes);

>> {A=5, B=17, C=1}

votes = sortByValue(votes);

System.out.println(votes);

>> {B=17, A=5, C=1}
Community
  • 1
  • 1
Jacob G.
  • 28,856
  • 5
  • 62
  • 116
  • This is good to order by value in reverse order, but what about breaking the tie? – fps Apr 16 '17 at 00:59
  • @FedericoPeraltaSchaffner For a tire, I don't quite understand what OP means regarding if they previously won the vote or not. Is there a variable that stores the information? If OP can clarify, then I can edit my answer. – Jacob G. Apr 16 '17 at 01:05
  • What I understand is that i.e. if there are 3 votes for Paul and 2 votes for Ann, and Ann is voted, then Ann needs to appear before Paul in the ordering, because Paul is the one who has previously wan the vote. Maybe @ctooley17 could clarify this... – fps Apr 16 '17 at 01:12
  • @JacobG. yes, there will be a string object that stores the name of the object that previously won the vote. So basically, is there is a tie between 2 objects, I want to make sure neither of them won previously, if they did I want to pick the one that didn't, if neither won, then I'll just pick one randomly. – ctooley17 Apr 16 '17 at 01:14
  • @FedericoPeraltaSchaffner What I mean is say on round 1 Paul gets 3 votes and Ann gets 2, Paul wins, but on round 2 if Paul AND Ann get 3 votes each, then choose Ann, because Paul won last time. – ctooley17 Apr 16 '17 at 01:15
0

To be able to determine the outcome of the tie, you would need more than just an integer. One solution could be to create a custom object that holds extra information and implements comparable (similar to what Walter said).

From what I can tell from your post, when there is a tied vote, you want the outcome to be the option that hasn't been picked as recently as the other tied options. If this is the case then the solution below, which uses Date as the secondary piece of information, should work.

import java.util.Date;

public class VoteOption implements Comparable<VoteOption>{

    private String name;
    private Integer votes;
    private Date lastVote;

    /** Constructor */
    public VoteOption(String name){
        this.name = name;
        this.lastVote = new Date();
        this.votes = 0;
    }

    /** gets the name of this option */
    public String name(){
        return this.name;
    }

    /** gets the number of votes this option currently has */
    public int votes(){
        return this.votes;
    }

    /** Call this method if the vote passed with this option.
     * It will update the lastVote date so that this will become the
     * last option to be picked if there is a tie in the next vote. */
    public void votePassed(){
        this.lastVote = new Date();
    }

    /** resets the vote count back to 0 */
    public void resetVoteCount(){
        this.votes = 0;
    }

    /** Adds 1 vote to the vote count */
    public void vote(){
        this.votes ++;
    }

    @Override
    public int compareTo(VoteOption otherOption){
        int compareVotes = this.votes.compareTo(otherOption.votes);
        if(compareVotes!=0){
            return compareVotes;
        } else {
            //handle vote ties
            int compareDates = this.lastVote.compareTo(otherOption.lastVote);
            return compareDates;
        }
    }
}

To sort a list of these options, you should call

Collections.sort(list);