Mark's MarkDown
  • notes
    • elevator pitch
    • cs
      • languages
        • elixir
          • data pipelines
            • broadway kafka
            • broadway
          • features
            • tree of contents
          • tips
            • enum
            • elixir tips
        • git
          • git notes

Tree of Contents

  • notes
    • elevator pitch
    • cs
      • languages
        • elixir
          • data pipelines
            • broadway kafka
            • broadway
          • features
            • tree of contents
          • tips
            • enum
            • elixir tips
        • git
          • git notes
Source
Résumé

Home

2022-10-03
The Elixir Enum Module
[all notes]

Enum

This is not the full list but in general, Enum module functions can be broken down into 3 main categories. see iex> h Enum. + tab for a full list.

  • 1. Cleansing data

    filter(), reject(), uniq() and uniq_by()

  • 2. Massaging data

    map(), group_by(), split_with(), sort_by() and with_index()

  • 3. Summarizing data

    reduce(), reduce_while(), frequencies() and frequencies_by()

Data Setup

languages list of maps

languages = [
 %{language: "Elixir", type: :concurrent},
 %{language: "Ruby", type: :not_concurrent},
 %{language: "Rust", type: :concurrent},
]

dogs list of maps

dogs =
 [
   %{id: 1, breed: "Pit Bull"}, 
   %{id: 1, breed: "Pit Bull"}, 
   %{id: 1, breed: "American Pit Bull Terrier"}, 
   %{id: 2, breed: "Great Pyrenees"}, 
   %{id: 2, breed: "Pyrenees"}, 
   %{id: 2, breed: "Pyrenees"}, 
   %{id: 3, breed: "Labrador"}
 ]

guitars list of maps

guitars = [
  %{year: 1967, maker: "Gibson", model: "Les Paul"},
  %{year: 2020, maker: "Fender", model: "Stratocaster"}, 
  %{year: 1994, maker: "Martin", model: "D-18"},
  %{year: 2000, maker: "Taylor", model: "D-28"},
  %{year: 2014, maker: "PRS", model: "Custom 24 Floyd"}, 
  %{year: 2023, maker: "PRS", model: "McCarty 594 Hollowbody II"}, 
  %{year: 1997, maker: "Parker", model: "Fly Deluxe"},
  %{maker: "Parker", model: "Fly Deluxe"},
]

1. Cleansing data

  • Enum.filter() ⬆︎

    Enum.filter(languages, fn 
      %{type: :concurrent} -> true
      _ -> false
    end)
    #[
    #  %{language: "Elixir", type: :concurrent},
    #  %{language: "Rust", type: :concurrent}
    #]

    languages list of maps

  • Enum.reject() ⬆︎

    Enum.reject(languages, fn lang ->
     match?(%{type: :not_concurrent}, lang)
    end)
    #[
    #  %{language: "Elixir", type: :concurrent},
    #  %{language: "Rust", type: :concurrent}
    #]
    
    # Enum.filter using a when guard
    Enum.filter(languages, fn
     %{language: lang} when lang in ["Rust", "Ruby"] -> true
     _ -> false
    end)
    #[
    #  %{language: "Rust", type: :concurrent}
    #  %{language: "Ruby", type: :not_concurrent},
    #]

    languages list of maps

  • Enum.uniq() ⬆︎

    Enum.uniq(dogs)
    #[
    #  %{breed: "Pit Bull", id: 1},
    #  %{breed: "American Pit Bull Terrier", id: 1},
    #  %{breed: "Great Pyrenees", id: 2},
    #  %{breed: "Pyrenees", id: 2},
    #  %{breed: "Labrador", id: 3}
    #]

    dogs list of maps

  • Enum.uniq_by() ⬆︎

    Enum.uniq_by(dogs, fn dog -> 
     dog.id
    end)
    #[
    #  %{breed: "Pit Bull", id: 1},
    #  %{breed: "Great Pyrenees", id: 2},
    #  %{breed: "Labrador", id: 3}
    #]
    
    # another way to write the above
    dogs |> Enum.uniq_by(&(&1.id))
    #[
    #  %{breed: "Pit Bull", id: 1},
    #  %{breed: "Great Pyrenees", id: 2},
    #  %{breed: "Labrador", id: 3}
    #]

    dogs list of maps

2. Massaging data

  • Enum.map() ⬆︎

    guitars
    |> Enum.map(fn
       %{year: year, maker: make, model: model} = entry
       when not is_nil(year) and not is_nil(make) and not is_nil(model) ->
         "#{year} #{make} #{model}" 
         _ -> 
           :invalid_data
    end)
    |> Enum.reject(fn 
       :invalid_data -> true
       _ -> false
    end)
    #[ 
    #  "1967 Gibson Les Paul", 
    #  "2020 Fender Stratocaster", 
    #  "1994 Martin D-18",
    #  "2000 Taylor D-28", 
    #  "2014 PRS Custom 24 Floyd",
    #  "2023 PRS McCarty 594 Hollowbody II", 
    #  "1997 Parker Fly Deluxe"
    #]

    guitars list of maps

  • Enum.group_by() ⬆︎

    guitars
    |> Enum.group_by(fn
        %{maker: make} -> make
    end)
    #%{
    #  "Fender" => [%{maker: "Fender", model: "Stratocaster", year: 2020}],
    #  "Gibson" => [%{maker: "Gibson", model: "Les Paul", year: 1967}],
    #  "Martin" => [%{maker: "Martin", model: "D-18", year: 1994}],
    #  "PRS" => [
    #    %{maker: "PRS", model: "Custom 24 Floyd", year: 2014},
    #    %{maker: "PRS", model: "McCarty 594 Hollowbody II", year: 2023}
    #  ],
    #  "Parker" => [
    #    %{maker: "Parker", model: "Fly Deluxe", year: 1997},
    #    %{maker: "Parker", model: "Fly Deluxe"}
    #  ],
    #  "Taylor" => [%{maker: "Taylor", model: "D-28", year: 2000}]
    #}

    guitars list of maps

  • Enum.split_with() ⬆︎

    guitars
    |> Enum.split_with(fn guitar ->
       Map.has_key?(guitar, :year)
    end)
    #{
    #  [
    #    %{maker: "Gibson", model: "Les Paul", year: 1967},
    #    %{maker: "Fender", model: "Stratocaster", year: 2020},
    #    %{maker: "Martin", model: "D-18", year: 1994},
    #    %{maker: "Taylor", model: "D-28", year: 2000},
    #    %{maker: "PRS", model: "Custom 24 Floyd", year: 2014},
    #    %{maker: "PRS", model: "McCarty 594 Hollowbody II", year: 2023},
    #    %{maker: "Parker", model: "Fly Deluxe", year: 1997}
    #  ], 
    #  [%{maker: "Parker", model: "Fly Deluxe"}]
    #}

    guitars list of maps

  • Enum.sort_by() ⬆︎

    guitars
    |> Enum.sort_by(fn
     %{year: year} -> year
     _ -> nil
    end)
    |> Enum.with_index(1)
    |> Enum.map(fn 
       {%{year: year, maker: make, model: model}, index} ->
         "#{index}, #{year} #{make} #{model}"
       {%{maker: make, model: model}, index} ->
         "#{index}, #{make} #{model}"
    end)
    
    #[
    #  "1, 1967 Gibson Les Paul", 
    #  "2, 1994 Martin D-18", 
    #  "3, 1997 Parker Fly Deluxe",
    #  "4, 2000 Taylor D-28", 
    #  "5, 2014 PRS Custom 24 Floyd",
    #  "6, 2020 Fender Stratocaster", 
    #  "7, 2023 PRS McCarty 594 Hollowbody II",
    #  "8, Parker Fly Deluxe"
    #]

    guitars list of maps

3. Summarizing data

  • Enum.reduce() with MapSet.new()

    guitars
    |> Enum.reduce(MapSet.new(), fn %{maker: make}, acc ->
        MapSet.put(acc, make)
    end)
    |> MapSet.to_list()
    
    #["Fender", "Gibson", "Martin", "PRS", "Parker", "Taylor"]

    guitars list of maps

  • Enum.reduce_while() ⬆︎

    guitars
    |> Enum.reduce_while(MapSet.new(), fn
       %{year: year}, acc -> 
         {:cont, MapSet.put(acc, year)}
       _, _ ->
         {:halt, {:error, "Missing year"}}
    end)
    #{:error, "Missing year"}
  • Enum.frequencies() ⬆︎

    guitars
    |> Enum.map(fn %{maker: make} -> make end)
    |> Enum.frequencies()
    #%{
    #  "Fender" => 1,
    #  "Gibson" => 1,
    #  "Martin" => 1,
    #  "PRS" => 2,
    #  "Parker" => 2,
    #  "Taylor" => 1
    #}

    guitars list of maps

  • Enum.frequencies_by() ⬆︎

    guitars
    |> Enum.map(fn %{maker: make} -> make end)
    |> Enum.frequencies_by(fn guitar -> 
       String.downcase(guitar)
    end)
    #%{
    #  "fender" => 1,
    #  "gibson" => 1,
    #  "martin" => 1,
    #  "parker" => 2,
    #  "prs" => 2,
    #  "taylor" => 1
    #}

    guitars list of maps