Enhancing a Voting System in Ruby

Introduction

Welcome back to another exciting session where we learn about enhancing existing functionality without causing regressions. Today, our scenario involves designing a voting system. We'll start with the basic implementation of the voting system and gradually introduce additional elements of complexity.

Starter Task Review

In our initial task, we created a simple voting system in Ruby with a set of basic functionalities:

  • register_candidate(candidate_id): This method is used to add new candidates to our system.
  • vote(timestamp, voter_id, candidate_id): This method facilitates users casting their votes. Each vote is given a timestamp.
  • get_votes(candidate_id): This method retrieves the total number of votes for a given candidate.
  • top_n_candidates(n): We also want to add a leaderboard functionality to our system. This method returns the top n candidates sorted by the number of votes.

Initial Solution Development

Let's jump into the Ruby code and begin the implementation of our starter task. Here, we use Ruby's built-in Hash and Array as the core of our design. These collections allow us to have dynamic lists keyed based on candidate IDs and voter IDs, which will greatly simplify our design.

class VotingSystem
  def initialize
    @candidates = {}  # Stores candidate_id as key and votes as value
    @voters = {}  # Tracks each voter's voting history
  end

  def register_candidate(candidate_id)
    return false if @candidates.key?(candidate_id)  # Candidate is already registered
    
    @candidates[candidate_id] = 0  # Initialize candidates with 0 votes
    true
  end

  def vote(timestamp, voter_id, candidate_id)
    return false unless @candidates.key?(candidate_id)  # Return false if candidate is not registered
    
    voter_history = @voters[voter_id] ||= { votes: [], timestamps: [] }
    voter_history[:votes] << candidate_id  # Record the vote
    voter_history[:timestamps] << timestamp  # Record the time of the vote
    @candidates[candidate_id] += 1  # Increment vote count for the candidate
    true
  end

  def get_votes(candidate_id)
    @candidates[candidate_id] || nil  # Retrieve vote count for a candidate or nil if not found
  end

  def top_n_candidates(n)
    @candidates.sort_by { |_, votes| -votes }
               .take(n)
               .map { |candidate_id, _| candidate_id }  # Return top n candidates based on votes
  end
end
Sign up

Join the 1M+ learners on CodeSignal

Be a part of our community of 1M+ users who develop and demonstrate their skills on CodeSignal