Home > Blockchain >  What am I missing for determining the winner by votes?
What am I missing for determining the winner by votes?

Time:11-07

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 
  • Related