kk.lau
kk.lau

Reputation: 47

Updating a dict value in Python

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

Answers (3)

Karl Knechtel
Karl Knechtel

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

Hailei
Hailei

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

ninjagecko
ninjagecko

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

Related Questions