I'm trying to think of a way to make functions that determine the winner of an election by most votes, as well as a function that determines a winner-takes-all rule.
My code is as follows:
_base_dict = {}
def add_state(name: str, votes: dict[str, int]) -> None:
global _base_dict
for name, votes in _base_dict.items():
_base_dict[name] = votes
def winner(college: dict[str, int]) -> str:
global _base_dict
rv = None
bigger_percentage = 0
for state, total_votes in college.items():
majority = total_votes // 2
for name, votes in _base_dict.items():
if votes[state] > majority:
percentage = votes[state] / float(total_votes)
if percentage > bigger_percentage:
bigger_percentage = percentage
rv = name
elif percentage == bigger_percentage:
rv = None
if rv is None:
return "No Winner"
return rv
def clear() -> None:
global _base_dict
_base_dict.clear()
_base_dict.update(_base_dict)
and on a test file, I am running the functions through this:
import elections
college = {'Virginia': 13,
'Ohio': 18,
'Minnesota': 10,
'Alabama': 9,
'Maine': 4
}
print(elections.winner({}))
elections.add_state('Virginia', {
'Turing': 15,
'Lovelace': 20,
'Dijkstra': 10
})
elections.add_state('Ohio', {
'Turing': 1,
'Dijkstra': 15
})
elections.add_state('Alabama', {
'Turing': 10,
'Lovelace': 20,
'Dijkstra': 8
})
print(elections.winner(college))
elections.add_state('Minnesota', {
'Lovelace': 10,
'Dijkstra': 30,
})
elections.add_state('Florida', {
'Turing': 10,
'Lovelace': 30,
'Dijkstra': 15
})
print(elections.winner(college))
elections.clear()
elections.add_state('Maine', {
'Turing': 2,
'Dijkstra': 1,
'Lovelace': 5
})
print(elections.winner(college))
My desired output is:
No Winner
Lovelace
Dijkstra
Lovelace
but I keep getting:
No Winner
No Winner
No Winner
No Winner
I do not know what I am doing wrong. Any help is appreciated. Edit: I prefer to use logic to solve this issue, though imports are also appreciated.
CodePudding user response:
I think this fixes it:
First off, I suggest _base_dict needs to be a defaultdict - so you can add keys to it that it doesn't already have. Like so:
from collections import defaultdict
_base_dict = defaultdict(lambda: defaultdict(lambda: 0))
Defined thus, every time you invoke _base_dict[<some state name>], if that state name is not already a key in _base_dict, the key gets added to _base_dict, and the value assigned to that key becomes another defaultdict whose keys will be candidate names, and whose vote count for that state will start off at 0.
Secondly, I'm uncomfortable with the global _base_dict business - that probably says more about me than about your code, but to keep my sanity I've worked around it by defining _base_dict at the beginning, and then passing it to add_state and winner on each of their calls. add_state takes in _base_dict, modifies it, and then returns it. This will probably drive functional programming aficionados crazy - and I apologise - I'm sure given more time I could come up with something a little more elegant.
def add_state(statename: str, statevotes: dict, _base_dict: dict) -> dict:
for candidatename, candidatevotes in statevotes.items():
_base_dict[statename][candidatename] = candidatevotes
return _base_dict
winner then takes in both college (a dict with state names for its keys and int for its values), and _base_dict - already defined above. I've rewritten winner below:
def winner(college: dict, _base_dict: dict) -> str:
rv = None
bigger_percentage = 0
for state, total_votes in college.items():
majority = total_votes // 2
for candidatename, candidatevotes in _base_dict[state].items():
if candidatevotes > majority:
percentage = candidatevotes / float(total_votes)
if percentage > bigger_percentage:
bigger_percentage = percentage
rv = candidatename
elif percentage == bigger_percentage:
rv = None
if rv is None:
return "No Winner"
return rv
I admit I haven't thought too deeply about the exact vote-counting logic here, I've simply adapted your original code to suit the changes I'm describing here.
Lastly, clear is redefined to accept _base_dict, and return it, like so:
def clear(_base_dict: dict) -> dict:
_base_dict.clear()
_base_dict.update(_base_dict)
return _base_dict
Putting it all together and running through the remainder of your script:
college = {'Virginia': 13,
'Ohio': 18,
'Minnesota': 10,
'Alabama': 9,
'Maine': 4
}
print(winner(college,_base_dict))
_base_dict = add_state('Virginia', {'Turing': 15,
'Lovelace': 20,
'Dijkstra': 10},
_base_dict)
_base_dict = add_state('Ohio', {'Turing': 1,
'Dijkstra': 15
},
_base_dict)
_base_dict = add_state('Alabama', {'Turing': 10,
'Lovelace': 20,
'Dijkstra': 8},
_base_dict)
print(winner(college, _base_dict))
_base_dict = add_state('Minnesota', {'Lovelace': 10,
'Dijkstra': 30,},
_base_dict)
_base_dict = add_state('Florida', {'Turing': 10,
'Lovelace': 30,
'Dijkstra': 15},
_base_dict)
print(winner(college, _base_dict))
_base_dict = clear(_base_dict)
_base_dict = add_state('Maine', {'Turing': 2,
'Dijkstra': 1,
'Lovelace': 5},
_base_dict)
print(winner(college, _base_dict))
We get:
No Winner
Lovelace
Dijkstra
Lovelace
Just as you expected.
CodePudding user response:
It's always helpful to draw out your data structure leads to less confusion. The issue can be resolved by adding a key to the dictionary if not already present else we can just update our dictionary with the new data.
_base_dict = {}
'''
'Turing': 'State1': Votes , 'State2': Votes, ...
'Lovelace': 'State': Votes , ...
'Dijkstra': ...
'''
class elections:
def add_state(state: str, data: dict[str, int]) -> None:
global _base_dict
for name, votes in data.items():
if(_base_dict.get(name) == None):
_base_dict[name] = {state: votes}
_base_dict[name].update({state: votes})
def winner(college: dict[str, int]) -> str:
global _base_dict
rv = None
bigger_percentage = 0
for state, total_votes in college.items():
majority = total_votes // 2
for name, votes in _base_dict.items():
# print(f"name:{name} votes:{votes}\n")
# print(f"state:{state} total_votes:{total_votes}")
try:
if votes[state] > majority:
percentage = votes[state] / float(total_votes)
if percentage > bigger_percentage:
bigger_percentage = percentage
rv = name
elif percentage == bigger_percentage:
rv = None
except:
pass
if rv is None:
return "No Winner"
return rv
def clear() -> None:
global _base_dict
_base_dict.clear()
_base_dict.update(_base_dict)
college = {'Virginia': 13,
'Ohio': 18,
'Minnesota': 10,
'Alabama': 9,
'Maine': 4
}
print(elections.winner({}))
elections.add_state('Virginia', {
'Turing': 15,
'Lovelace': 20,
'Dijkstra': 10
})
elections.add_state('Ohio', {
'Turing': 1,
'Dijkstra': 15
})
elections.add_state('Alabama', {
'Turing': 10,
'Lovelace': 20,
'Dijkstra': 8
})
print(elections.winner(college))
elections.add_state('Minnesota', {
'Lovelace': 10,
'Dijkstra': 30,
})
elections.add_state('Florida', {
'Turing': 10,
'Lovelace': 30,
'Dijkstra': 15
})
print(elections.winner(college))
elections.clear()
elections.add_state('Maine', {
'Turing': 2,
'Dijkstra': 1,
'Lovelace': 5
})
print(elections.winner(college))
No Winner
Lovelace
Dijkstra
Lovelace
