Reputation: 47
The assignment is written in the docstring by my prof:
def evaluateBallot (voterPreferences, candidates):
"""
Using voterPreferences (a dict associating each voter with a list of
candidate names ordered from highest to lowest preference) and
candidates(a set of candidates still remaining in the election),
returns the vote distribution: a dict associating the name of each
candidate in the election to the number of votes that they received
>>> result = evaluateBallot(dict(x=['a','b','c'], y=['a','c','b'],z= ['c','a','b']),set(['b','c']))
>>> (result['b'],result['c'])
(1, 2)
"""
d ={}
for candidate in candidates:
d[candidate] = 0
for voterPreference in voterPreferences:
if candidate == voterPreference[0]:
d[candidate] += 1
return d
When I run the code I wrote, the dictionary does not update +1 for each time the candidate is a voter's top choice. I feel like the error is in my if statement, but I'm not sure what it is exactly?
Upvotes: 1
Views: 349
Reputation: 61478
for candidate in candidates:
d[candidate] = 0
After this loop finishes, candidate
has the value of whatever candidate was last in candidates
.
for voterPreference in voterPreferences:
if candidate == voterPreference[0]:
d[candidate] += 1
In this loop, we use that leftover candidate
value, and only update votes for that candidate.
I assume what you wanted to do is check that voterPreference[0]
is a valid candidate. To do that, we can check if the voterPreference[0]
is in
the existing d
, and update accordingly:
for voterPreference in voterPreferences:
if voterPreference[0] in d:
d[voterPreference[0]] += 1
We can simplify this by using tuple unpacking for voterPreference
, if we know how many items long it is, or by assigning voterPreference[0]
to another variable. Also, your 3-space indent is non-standard; please consider switching to 4 :)
Upvotes: 0
Reputation: 42163
If the data is like what you described in the comments, then I think
for voterPreference in voterPreferences:
should be changed to
for voterPreference in voterPreferences.values():
since what you want voterPreference to be is ['a','b','c'] but not 'x'.
P.S. I don't quite understand why the output should be b=1 and c=2. How do you want to handle with a if it doesn't exist in candidates but exists in voterPreferences? Ignoring it? If so you need more logic in your method to handle this.
Additional
By your comments it seems that non-candidates should be ignored when calculating the final result:
def evaluateBallot(voterPreferences, candidates):
d = {}
voterPrefCandOnly = [] # Just use list since we don't care about who voted
# Remove votes for non-candidates
for voterPref in voterPreferences.values():
filtered = filter(lambda x: x in cand, voterPref)
voterPrefCandOnly.append(filtered)
# Calculate the result for voting
for candidate in candidates:
d[candidate] = 0
for voterPref in voterPrefCandOnly:
if candidate == voterPref[0]:
d[candidate] += 1
return d
voterPref = dict(x=['a','b','c'], y=['a','c','b'], z=['c','a','b'])
cand = set(['b','c'])
result = evaluateBallot(voterPref, cand)
print (result['b'], result['c']) # (1, 2)
Upvotes: 1
Reputation: 91094
I believe the assignment assumes the reader takes for granted a particular kind of runoff voting. And thus it seems likely the teacher is also implying that "each person will cast exactly one vote, and that vote will go to their highest-rated candidate which is in candidates
"
This is a complete answer you can check your work against when finished, or if you get stuck for a long time, or wish to check your assumptions:
def evaluateBallot(voterPreferences, candidates):
"""
. . .
"""
votes = collections.Counter() # or collections.defaultdict(lambda: 0)
for voter,prefOrdering in voterPreferences.items():
for desiredCandidate in prefOrdering: # go through each person's preference list
if desiredCandidate in candidates: # if candidate is still in the running
# then this person votes for that candidate
votes[desiredCandidate] += 1
break
# it is possible that the person casts no votes
return dict(votes)
Upvotes: 0