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