-1

Code:

candidates_and_fp_votes = {'a': 25, 'b': 0, 'c': 17, 'd': 23, 'e': 0}

print(candidates_and_fp_votes)
final_vals = [a for a, b in candidates_and_fp_votes.items() if
              list(candidates_and_fp_votes.values()).count(b) > 1]
print("Duplicates are: ")
for i in final_vals:
    print(i)
print(final_vals)

if not final_vals:
    print("No tiebreaker sys required")
else:
    print("Tie-breaker required")

Currently, this outputs "Tie-breaker required" as 'b' and 'e' have a value of 0. I would like this so it only finds duplicates that affect the highest or second highest value. Eg:

  1. Right now, it should print "No tiebreaker sys required because even if there is a duplicate with 'b' and 'e' it is not a duplicate with the second and highest values '25' and '23'

  2. if the dict to be = {'a': 25, 'b': 0, 'c': 23, 'd': 23, 'e': 0} it would print out "Tie-breaker required as it is affecting the 2nd highest value - 23.

Also, I just had a little change in mind, if the highest score is duplicating with a number but this number does not duplicate with the second highest, it would just output "No tiebreaker sys required"

How can I do this?

Thanks in advance.

TIC-FLY
  • 125
  • 1
  • 10
  • What have you done so far? How do you find the highest two values in a collection? Given that, how do you find those values in your dictionary? – Prune Nov 15 '17 at 19:05
  • I don't know the answer to your questions. But what I have attempted is the code which is stated im the question. – TIC-FLY Nov 15 '17 at 19:08

5 Answers5

1

If the 2nd highest value in candidates_and_fp_votes is having a tie, then it prints "Tie-breaker required".

#candidates_and_fp_votes = {'a': 25, 'b': 0, 'c': 17, 'd': 23, 'e': 0}

candidates_and_fp_votes = {'a': 25, 'b': 0, 'c': 23, 'd': 23, 'e': 0}
    print(candidates_and_fp_votes)
final_vals = [ b for a, b in candidates_and_fp_votes.items() if list(candidates_and_fp_votes.values()).count(b) > 1]
dup=sorted(set(final_vals), reverse=True)

act=sorted(set(list(candidates_and_fp_votes.values())), reverse=True)

print("duplicates: ", dup)
print("actual:     ", act)

if dup:
    if dup[0] == act[0]:
        del act[0]
        del dup[0]

if dup:
    if dup[0] == act[0] or dup[0] == act[1]:
        print("Tie breaker required")
    else:
        print("No tie breaker required")
else:
    print("No tie breaker required")
Van Peer
  • 2,127
  • 2
  • 25
  • 35
  • Does this find if there is a duplicate with the highest score or is it for both the highest and the second highest? – TIC-FLY Nov 15 '17 at 19:11
  • Also, I just had a little change in mind, if the highest score is duplicating with a number but this number does not duplicate with the second highest, it would just output "No tiebreaker sys required" – TIC-FLY Nov 15 '17 at 19:28
  • 1
    Thank you but I have found another answer that is more efficient, I will still upvote your answer. Thanks again and sorry for any inconvenience. – TIC-FLY Nov 15 '17 at 20:21
1

Just preserve a and b to take the rigth choice:

candidates_and_fp_votes =  {'a': 25, 'c': 25, 'b': 0, 'e': 23, 'd': 23}

print(candidates_and_fp_votes)
final_vals = [[a,b] for a, b in candidates_and_fp_votes.items() if
              list(candidates_and_fp_votes.values()).count(b) > 1]
print("Duplicates are: ")
for i in final_vals:
    print(i)

fAndS=sorted(candidates_and_fp_votes.values())[len(candidates_and_fp_votes)-2:len(candidates_and_fp_votes)]
maxVals=[[a,b] for a, b in candidates_and_fp_votes.items() if b==max(candidates_and_fp_votes.values())]
if final_vals:
    print("There is a duplicate with")
    print(final_vals)

if len(maxVals)==2:
    print("2 highest scoring candidates are equal")
    print(maxVals)
    print("No tiebreaker sys required")
else:
    final_vals = [ a for a,b in final_vals if b in fAndS]
    if not final_vals:
        print("It is not a duplicate with the second and highest values")
        print(fAndS)
        print("No tiebreaker sys required")
    else:
        print("There is a duplicate with the second and highest values")
        print(fAndS)
        print("Tie-breaker required")

Output 1:

{'a': 25, 'c': 17, 'b': 0, 'e': 0, 'd': 23}
Duplicates are: 
['b', 0]
['e', 0]
There is a duplicate with
[['b', 0], ['e', 0]]
It is not a duplicate with the second and highest values
[23, 25]
No tiebreaker sys required

Output 2:

{'a': 25, 'c': 23, 'b': 0, 'e': 0, 'd': 23}
Duplicates are: 
['c', 23]
['b', 0]
['e', 0]
['d', 23]
There is a duplicate with
[['c', 23], ['b', 0], ['e', 0], ['d', 23]]
There is a duplicate with the second and highest values
[23, 25]
Tie-breaker required

Output 3:

{'a': 25, 'c': 25, 'b': 0, 'e': 23, 'd': 23}
Duplicates are: 
['a', 25]
['c', 25]
['e', 23]
['d', 23]
There is a duplicate with
[['a', 25], ['c', 25], ['e', 23], ['d', 23]]
2 highest scoring candidates are equal
[['a', 25], ['c', 25]]
No tiebreaker sys required

[EDIT] Here is a more simple answer, just thinking all conditions together: (Based only the dict sorted)

candidates_and_fp_votes =  {'a': 25, 'c': 25, 'b': 0, 'e': 0, 'd': 23}
sorted_votes = sorted([[value,key] for key,value in candidates_and_fp_votes.items()])

resultList=[]
dictSize = len(candidates_and_fp_votes)
print sorted_votes
if(dictSize>=3):
  if sorted_votes[dictSize-2][0]==sorted_votes[dictSize-3][0]:
    print("Need tie break between")
    resultList = [ key for value,key in sorted_votes if value==sorted_votes[dictSize-2][0] ]
    print resultList
  else:
    print("Winers")
    resultList = [key for value,key in sorted_votes[dictSize-2:dictSize]]
    print resultList

Output:

[[0, 'b'], [0, 'e'], [23, 'd'], [25, 'a'], [25, 'c']]
Winers
['a', 'c']
Rama
  • 3,222
  • 2
  • 11
  • 26
  • There is a problem if d and b are 23. It prints: Even if there is a duplicate with [['b', 23], ['d', 23]] It is not a duplicate with the second and highest values [23, 25] which is not really what i'm looking for. – TIC-FLY Nov 15 '17 at 19:46
  • Where do i put this chunk? Could you please post the whole code with the chunk added in? – TIC-FLY Nov 15 '17 at 19:49
  • I'm sorry if i'm a pest but could you make it so if the highest score is duplicating with a number but this number does not duplicate with the second highest, it would just output "No tiebreaker sys required"? I'm sorry for any inconvenience, it was just me thinking a bit wrong before. Because if the point of this code is to find the 2 highest scoring candidates and if there is a tie, than to move onto another function which I have already wrote.And if the highest scoring candidate is the same as the second, we have already found the 2 winners so there is no point going into a tiebreaker. – TIC-FLY Nov 15 '17 at 19:53
  • If this manages to work, I will most certainly give it a tick above the others as yours will be the best and the most hard work put into it. :D – TIC-FLY Nov 15 '17 at 19:55
  • If you don't understand any of my analogy's or anything else, feel free to ask. – TIC-FLY Nov 15 '17 at 20:00
  • @TIC-FLY Edited to meet that you say – Rama Nov 15 '17 at 20:12
  • I cannot express how happy I am. Thanks you very much of your time, if I could give you 1000 reputation, I would give you 100000. I really appreciate all that you have done to help me and all of the hard work it must have taken you. Thanks again and sorry for any inconvenience caused. – TIC-FLY Nov 15 '17 at 20:17
  • @TIC-FLY You are welcome, btw i add more simple solution at the end just in case you want to use it – Rama Nov 15 '17 at 21:06
  • Is there a way to set [[23, 'c'], [23, 'd']] to just be ['c', 'd'] and set that to a list? – TIC-FLY Nov 15 '17 at 21:15
  • @TIC-FLY yeah... it easy to print just the keys. Edited – Rama Nov 16 '17 at 13:27
  • I meant can you turn the tiebreaker required candidates from a print statement to a list with just the keys of them in. Thanks in advance. – TIC-FLY Nov 16 '17 at 15:22
  • @TIC-FLY And more easy to set that to a list.. Edited. See this for more information. http://www.thegeekstuff.com/2013/06/python-list/?utm_source=feedly – Rama Nov 16 '17 at 15:37
0

To find the duplicates that are the maximum of the values or the second highest, you can try this:

candidates_and_fp_votes = {'a': 25, 'b': 0, 'c': 17, 'd': 23, 'e': 0}
tie_breakers = [a for a, b in candidates_and_fp_votes.items() if list(candidates_and_fp_votes.values()).count(b) > 1 and b in [d for c, d in sorted(candidates_and_fp_votes.items(), key=lambda x:x[-1])[-2:]]]

Output:

['c', 'd']
Ajax1234
  • 69,937
  • 8
  • 61
  • 102
  • The output is wrong, here it should output that a tiebreaker is not required as the 2 highest numbers are not a duplicate of another number. – TIC-FLY Nov 15 '17 at 19:06
  • It threw the error: AttributeError: 'dict_values' object has no attribute 'count' – TIC-FLY Nov 15 '17 at 19:19
  • Also, I just had a little change in mind, if the highest score is duplicating with a number but this number does not duplicate with the second highest, it would just output "No tiebreaker sys required". – TIC-FLY Nov 15 '17 at 19:23
0

You can use heapq.nlargest to find the three largest values and then inspect them:

import heapq
max3 = heapq.nlargest(3, candidates_and_fp_votes.values())

max3 will now contain the three largest values (preserving multiple occurrences) in descending order. The rest should be easy.

Paul Panzer
  • 51,835
  • 3
  • 54
  • 99
  • So, after this, how would I check if any of the 3 are duplicates? – TIC-FLY Nov 15 '17 at 19:12
  • @TIC-FLY Well, you compare them: For example `if max3[1] == max3[2]:` Then the second and third largest are the same, so you would requirer a tie-breaker. – Paul Panzer Nov 15 '17 at 19:16
  • What is max3[0] = max3[1] = max3[2]? I'm just looking for a way to make this efficient and to work in all scenarios of duplicates with the highest and second highest scores. – TIC-FLY Nov 15 '17 at 19:18
  • @TIC-FLY that case is contained in the one i mentioned (because if the first three are equal, then, of course, the second and the third are equal). I'm not sure what you want to do if the first two are equal but the third is different. – Paul Panzer Nov 15 '17 at 19:49
-1

As I understand it, you are looking to determine a winner based on the highest number of votes and whether a tie breaker is necessary. You could do that like this:

import operator
candidates_and_fp_votes = {'a': 25, 'b': 0, 'c': 17, 'd': 23, 'e': 0}
sorted_candidates = sorted(candidates_and_fp_votes.items(), key=operator.itemgetter(1), reverse=True)

The output of sorted_candidates will look like:

[('a', 25), ('d', 23), ('c', 17), ('b', 0), ('e', 0)]

You can then iterate over this:

tie = False
for idx, _ in enumerate(sorted_candidates):
     candidate, votes = sorted_candidates[idx]
     next_candidate, next_votes = sorted_candidates[idx+1]

     if votes > next_votes:
         if tie is True:
             print("Tie Breaker needed!")
         else:
             print(f"Candidate {candidate} is the Winner!")
         break

     elif votes == next_votes:
         print("Tie!")
         tie = True

Just one of many ways to get there. I hope that helps.

Reference:

Edit:

You are asking to determine if the is a tie. My approach would be to reverse the dict. Making the votes the key and creating a list of candidates that have an equal number of votes. Something like this:

from collections import defaultdict
reversed_dict = defaultdict(list)
for key,value in candidates_and_fp_votes.items():
    reversed_dict[value].append(key)

Outputting:

defaultdict(list, {0: ['b', 'e'], 17: ['c'], 23: ['d'], 25: ['a']})

Any key that has a candidate value-list of len > 1 needs a tie breaker.

Shawn
  • 561
  • 1
  • 5
  • 12
  • The thing with this is that there are supposed to be 2 winners, the highest and 2nd highest scoring candidate. – TIC-FLY Nov 15 '17 at 19:34
  • Well, since my example compares the current candidate to the next candidate, if you want the top two, just tweak the code to output both the current and the next candidate :) – Shawn Nov 15 '17 at 19:36
  • Further tweaked my response. I hope it is helpful. – Shawn Nov 15 '17 at 19:57