Home > Net >  Output election winner in the presence of ties
Output election winner in the presence of ties

Time:01-07

I have programmed a working voting system, but it needs a little more decision making involved. The program needs to work if two or more candidates have the same number of votes.

Below is what i have but i think it is very long winded, and it will only work with 2 candidates having the same number of votes. Is there a more efficient way of doing this while working with 2 or more candidates having the same votes.

There are only 5 candidates available in this scenario, but should work if more are added too.

public static void displayFinalResults(String[] stringArray, int[] numArray){
        if(numArray[0] == numArray[1]){
            System.out.println("\nIn third place: "   stringArray[3]);
            System.out.println("In second place: "   stringArray[2]);
            System.out.println("And the winner is: "   stringArray[0]   " and "   stringArray[1]);

        }else if(numArray[1] == numArray[2]){
            System.out.println("\nIn third place: "   stringArray[3]);
            System.out.println("In second place: "   stringArray[1]   " and "   stringArray[2]);
            System.out.println("And the winner is: "   stringArray[0]);
        }else if(numArray[2] == numArray[3]){
            System.out.println("\nIn third place: "   stringArray[2]   " and "   stringArray[3]);
            System.out.println("In second place: "   stringArray[1]);
            System.out.println("And the winner is: "   stringArray[0]);
        }else{
            System.out.println("\nIn third place: "   stringArray[2]);
            System.out.println("In second place: "   stringArray[1]);
            System.out.println("And the winner is: "   stringArray[0]);
        }

    }

CodePudding user response:

I'd first check what are the scores, highest, second highest, third highest. And then pick the names which have these values

public static void displayFinalResults(String[] stringArray, int[] numArray){
    int highestScore = max(numArray, Integer.MAX_VALUE);
    int secondHighestScore = max(numArray, highestScore);
    int thirdHighestScore = max(numArray, secondHighestScore);

    System.out.println("\nIn third place: ");
    for (int i = 0; i < numArray.length; i  ) {
        if (numArray[i] == thirdHighestScore) {
            System.out.println(stringArray[i]);
        }
    }

    System.out.println("In second place: ");
    for (int i = 0; i < numArray.length; i  ) {
        if (numArray[i] == secondHighestScore) {
            System.out.println(stringArray[i]);
        }
    }

    System.out.println("And the winner: ");
    for (int i = 0; i < numArray.length; i  ) {
        if (numArray[i] == highestScore) {
            System.out.println(stringArray[i]);
        }
    }

}

public static int max(int[] scores, int lessThan) {
    int max = Integer.MIN_VALUE;
    for (int score : scores) {
        if (score > max && score < lessThan) {
            max = score;
        }
    }

    return max;
}

CodePudding user response:

This is approach I would take. I would create a structure to hold the candidate name and number of votes as tracking that across 2 arrays is complicated and might be confusing. I would also suggest to use different data structures than arrays as the method input, I converted the input in the example into stream of Candidate which has 2 fields name and numVotes:

    record Candidate(String name, int numVotes) {
    }

    public static void displayFinalResults(String[] stringArray, int[] numArray) {
        //make sure that 2 arrays match in size
        assert numArray.length == stringArray.length;
        //zip arrays and convert to the stream of Candidate
        var candidates = IntStream.range(0, stringArray.length).mapToObj(i -> new Candidate(stringArray[i], numArray[i]));
        //group by number of votes
        var groupedByNumVotes = candidates.collect(Collectors.groupingBy(c -> c.numVotes));
        //sort by number of votes descending
        var sorded = groupedByNumVotes.entrySet().stream().sorted((e1, e2) -> Integer.compare(e2.getKey(), e1.getKey()));
        //take first 3 places
        var winners = sorded.limit(3).toList();

        //Loop through the list of winners with index and print it
        for (int i = 0; i < winners.size(); i  ) {
            //List is indexed from 0 so the place number needs to be increased by one
            System.out.println("Place "   (i   1));  
            winners.get(i).getValue().forEach(System.out::println);
            System.out.println();
        }
    }

CodePudding user response:

Frankly, there is nothing fundamentally wrong with your approach (except that, by convention, the second place is usually skipped if there is a tie for the first; that is: there are two tied first-place candidates and a third place, but no second place). You just need to add one more case for three tied candidates.

That said, you can slightly shorten the code by merging redundancies in output formatting:

public static void displayFinalResults(String[] names, int[] scores) {
    final String[] winners = new String[3];

    if (scores[0] == scores[1] && scores[1] == scores[2]) {
        winners[0] = String.format("%s, %s and %s", names[0], names[1], names[2]);
    } else if (scores[0] == scores[1]) {
        winners[0] = String.format("%s and %s", names[0], names[1]);
        winners[2] = names[2];
    } else if (scores[1] == scores[2]) {
        winners[0] = names[0];
        winners[1] = String.format("%s and %s", names[1], names[2]);
    } else {
        System.arraycopy(names, 0, winners, 0, 3);
    }

    System.out.println();
    if (winners[2] != null) System.out.printf("In third place: %s\n", winners[2]);
    if (winners[1] != null) System.out.printf("In second place: %s\n", winners[1]);
    final String prefix = winners[2] == null && winners[1] == null ? "T" : "And t";
    System.out.printf("%she winner is: %s\n", prefix, winners[0]);
}
  • Related