Skip to content

Instantly share code, notes, and snippets.

@Billboz
Last active October 16, 2022 10:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Billboz/43242d4a76634c661961e8459392ef9b to your computer and use it in GitHub Desktop.
Save Billboz/43242d4a76634c661961e8459392ef9b to your computer and use it in GitHub Desktop.
Some code stubs for a livebook to do with Enum drills

Drill: Replace nils in A List With Elements From A 2nd List

Mix.install([
  {:youtube, github: "brooklinjazz/youtube"},
  {:hidden_cell, github: "brooklinjazz/hidden_cell"},
  {:tested_cell, github: "brooklinjazz/tested_cell"},
  {:utils, path: "#{__DIR__}/../utils"}
])

Navigation

Return Home Report An Issue

Purpose

This is a drill exercise:

Drill exercises are meant to provide practise of Elixir's syntax and important language modules so developers can type them out as fast as possible. The problem should not be conceptually difficult to facilitate this goal.

Developers need to commit both Elixir's syntax and core modules/functions to (working) memory so that when writing their code the developer is not slowed down having to remember the syntax or which module function to use. This is analogous to knowing how to spell and the grammar of your (human) language.

To develop familiarity with the Enum module, you will replace nil values in a list with values from a second list at the same index.

For example:

list1 = [0, nil, 2, 3, nil]
list2 = [:a, :b, :c, :d, :e]

ReplaceNils.replace(list1, list2)
[0, :b, 2, 3, :e]

You can assume the lists are of the same length.

Implement the ReplaceNils module as below:

input1 = [nil, 3, nil, nil, nil, nil, nil, nil, nil, nil]
input2 = [:a, :b, :c, :d, :e, :f, :g, :h, :i, :j]

defmodule ReplaceNils do
  # def replace(target_list, source_list) do
  #   Enum.map(t_elem, fn t_elem ->    # this can't work because each of the 
  #     Enum.map(s_elem, fn s_elem ->  # first lists elem's iterates over 
  #       case {t_elem, s_elem} do     # the entire second list
  #         {nil, s_elem} -> s_elem    # My sense is I can make this work
  #         {t_elem, s_elem} -> t_elem
  #       end
  #     end)
  #   end)
  # end

  def replace(target_list, source_list) do
    target_list
    |> Enum.with_index()
    |> Enum.map(fn {t_elem, t_index} ->
      if t_elem == nil do
        Enum.at(source_list, t_index)
      else
        t_elem
      end
    end)

    # |> dbg
  end

  # def replace(target_list, source_list) do
  #   target_elem_or_source_elem = fn {t_elem, s_elem} -> t_elem || s_elem end

  #   [target_list, source_list]
  #   |> Enum.zip()
  #   |> Enum.map(target_elem_or_source_elem)
  # end
end

ReplaceNils.replace(input1, input2)
target_list = [nil, 3, nil, nil, nil, nil, nil, nil, nil, nil]
source_list = [:a, :b, :c, :d, :e, :f, :g, :h, :i, :j]
# Enum.zip([target_list, source_list])
Enum.with_index(target_list)
nil || :a
3 || :b

Here are some additional test data to think about:

Testcase 1:
  Input1:   [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
  Input2:   [nil, nil, nil, nil, nil, nil, nil, nil, nil, nil]
  Expected: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

Testcase 2:
  Input1:   [nil, nil, nil, nil, nil, nil, nil, nil, nil, nil]
  Input2:   [:a, :b, :c, :d, :e, :f, :g, :h, :i, :j]
  Expected: [:a, :b, :c, :d, :e, :f, :g, :h, :i, :j]

Testcase 3:
  Input1: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
  Input2: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

Testcase 4:
  Input1: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
  Input2: [:a, :b, :c, :d, :e, :f, :g, :h, :i, :j]

Testcase 5:
  [1, 2, 3, nil, nil, 6, 7, nil, 9, 10]
  [:a, :b, :c, :d, :e, :f, :g, :h, :i, :j]
First Hint
Consider combining at least one of the Enum functions
you have already learned with Enum functions you have
not been exposed to but can find in the Enum
documentation.
Second Hint
Take a look at Enum.with_index.  What does it produce
when applied to the target list?
What will use this output to compare and replace 
elements from the two lists and output one list?

Here are some example solutions:

Example Solution 1
Enum.at is fine for small lists but has performance
challenges with larger lists.
Can you refactor this code to not use Enum.at?

defmodule ReplaceNils do
  def replace(input1, input2) do
    input1
    |> Enum.with_index()
    |> Enum.map(fn {element, index} ->
      if element == nil do
        Enum.at(input2, index)
      else
        element
      end
    end)
  end
end
First Hint - Refactor
place hint here
Example Solution 2
defmodule ReplaceNils do
  def replace(as, bs) do
    a_or_b = fn {a, b} -> a || b end

    [as, bs]
    |> Enum.zip()
    |> Enum.map(a_or_b)
  end
end
Possibilities
Here are some other Enum functions to
consider:
Enum.?
Enum.?

Commit Your Progress

Run the following in your command line from the beta_curriculum folder to track and save your progress in a Git commit.

$ git add .
$ git commit -m "finish saferange exercise"

Up Next

Previous Next
A Safe Range Non-Enumerables
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment