Powered by AppSignal & Oban Pro

Weighted Voting

exercises/weighted_voting.livemd

Weighted Voting

Mix.install([
  {:jason, "~> 1.4"},
  {:kino, "~> 0.8.0", override: true},
  {:youtube, github: "brooklinjazz/youtube"},
  {:hidden_cell, github: "brooklinjazz/hidden_cell"}
])

Navigation

Return Home Report An Issue

Weighted Voting

In the previous Counting Votes exercise, we created a module to count a list of votes. For example, users would vote for their favorite animal to decide if :birds, :dogs, or :cats were more popular.

Now, you’re going to create a WeightedVoting.count/2 that can count the number of votes for a single value such as :dogs or :cats. provided in a keyword list.

WeightedVoting.count([cats: 10, dogs: 20, dogs: 20], :dogs)
40

You’re also going to create a WeightedVoting.tally/1 function that will count the votes provided in a keyword list, and return the results as a keyword list like so.

WeightedVoting.tally([cats: 10, dogs: 20, dogs: 20])
[cats: 10, dogs: 40]

Example Solution

defmodule WeightedVoting do
  def count(votes, vote_to_count) do
    Enum.reduce(votes, 0, fn {key, value}, acc ->
      if key == vote_to_count do
        acc + value
      else
        acc
      end
    end)
  end

  def tally(votes) do
    Enum.reduce(votes, [], fn {key, vote_count}, acc ->
      Keyword.update(acc, key, vote_count, fn existing_value ->
        existing_value + vote_count
      end)
    end)
  end

  def tally_map(votes) do
    Enum.reduce(votes, %{}, fn {key, vote_count}, acc ->
      Map.update(acc, key, vote_count, fn existing_value ->
        existing_value + vote_count
      end)
    end)
  end
end

Implement the WeightedVoting module as documented below.

defmodule WeightedVoting do
  @doc """
  Count the total number of votes for some key in a keyword list.

  ## Examples

    iex> WeightedVoting.count([dogs: 20, dogs: 10], :dogs)
    30
    iex> WeightedVoting.count([cats: 10, dogs: 20, dogs: 30], :dogs)
    50
    iex> WeightedVoting.count([cats: 10, dogs: 20, dogs: 10, cats: 30], :cats)
    40
  """
  def count(votes, vote_to_count) do
  end

  @doc """
  Tally the total number of votes in a keyword list, and return
  the results as a keyword list.

  The keyword list should be sorted in alphabetical order.

  ## Examples

    iex> WeightedVoting.tally([dogs: 20, dogs: 10])
    [dogs: 30]
    iex> WeightedVoting.tally([cats: 10, dogs: 20, dogs: 10])
    [cats: 10, dogs: 30]
    iex> WeightedVoting.tally([cats: 10, dogs: 20, cats: 20, dogs: 10, birds: 20])
    [birds: 20, cats: 30, dogs: 30]
  """
  def tally(votes) do
  end
end

Bonus: Tally Map

Create a WeightedVoting.tally_map/1 function which returns a map instead of a keyword list. You may copy the following code into the WeightedVoting module above to get started.

  @doc """
  Tally the total number of votes in a keyword list, and return
  the results as a map.

  ## Examples

    iex> WeightedVoting.tally_map([dogs: 20, dogs: 10])
    %{dogs: 30}
    iex> WeightedVoting.tally_map([cats: 10, dogs: 20, dogs: 10])
    %{cats: 10, dogs: 30}
    iex> WeightedVoting.tally_map([cats: 10, dogs: 20, cats: 20, dogs: 10, birds: 20])
    %{birds: 20, cats: 30, dogs: 30}
  """
  def tally_map(votes) do
  end

Mark As Completed

file_name = Path.basename(Regex.replace(~r/#.+/, __ENV__.file, ""), ".livemd")

save_name =
  case Path.basename(__DIR__) do
    "reading" -> "weighted_voting_reading"
    "exercises" -> "weighted_voting_exercise"
  end

progress_path = __DIR__ <> "/../progress.json"
existing_progress = File.read!(progress_path) |> Jason.decode!()

default = Map.get(existing_progress, save_name, false)

form =
  Kino.Control.form(
    [
      completed: input = Kino.Input.checkbox("Mark As Completed", default: default)
    ],
    report_changes: true
  )

Task.async(fn ->
  for %{data: %{completed: completed}} <- Kino.Control.stream(form) do
    File.write!(
      progress_path,
      Jason.encode!(Map.put(existing_progress, save_name, completed), pretty: true)
    )
  end
end)

form

Commit Your Progress

Run the following in your command line from the curriculum folder to track and save your progress in a Git commit. Ensure that you do not already have undesired or unrelated changes by running git status or by checking the source control tab in Visual Studio Code.

$ git checkout -b weighted-voting-exercise
$ git add .
$ git commit -m "finish weighted voting exercise"
$ git push origin weighted-voting-exercise

Create a pull request from your weighted-voting-exercise branch to your solutions branch. Please do not create a pull request to the DockYard Academy repository as this will spam our PR tracker.

DockYard Academy Students Only:

Notify your teacher by including @BrooklinJazz in your PR description to get feedback. You (or your teacher) may merge your PR into your solutions branch after review.

If you are interested in joining the next academy cohort, sign up here to receive more news when it is available.

Up Next

Previous Next
Number Finder Custom Enum With Reduce