function: group_by

My Favorite Functions and Patterns: group_by

Thank you for joining me as I share my favorite functions and patterns in functional programming. Today’s focus is on the function group_by. Previously, I published Function: with Statement and Function: Curry. This is the third installation in the series. For all of this week’s functions and patterns,  visit the Index.

I encountered this little gem while pair-programming with a colleague. It affords much potential in the domain of complex sorting operations.

Say we’ve a large list of unsorted, unordered exam results:

def list_exam_results do
  [
    %{name: "Zelda", score: 56},
    %{name: "Eddy", score: 58},
    %{name: "Jack", score: 69},
    %{name: "Abby", score: 84},
    %{name: "Lily", score: 96}
  ]
end

First, we want to segregate records by letter grade (e.g., A, B, C, D, F), and then, for each group, we want to order results by student name. Elixir’s Enum.group_by is perfect.

Implementations of group_by generally take a list of items and then a predicate. Our predicate might look something like:

def by_grade(%{score: score}) do
  cond do
    score < 65 -> "F"
    score < 70 -> "D"
    score < 80 -> "C"
    score < 90 -> "B"
    true -> "A"
  end
end

Which will take any of our records from list_exam_results and return a letter grade. On its own:

Enum.group_by(list_exam_results(), &by_grade(&1))

Will return:

%{
  "A" => [%{name: "Lily", score: 96}],
  "B" => [%{name: "Abby", score: 84}],
  "D" => [%{name: "Jack", score: 69}],
  "F" => [%{name: "Zelda", score: 56}, %{name: "Eddy", score: 58}]
}

We’ve now positioned our data so that its subsets can be sorted by letter grade. Our final group_byimplementation might resemble:

def prepare_records(coll \\ list_exam_results()) do
  coll
  |> Enum.group_by(&by_grade(&1))
  |> Enum.map(fn {_letter_grade, subset} -> Enum.sort(subset) end)
end

Which will give us:

[
  [%{name: "Lily", score: 96}],
  [%{name: "Abby", score: 84}],
  [%{name: "Jack", score: 69}],
  [%{name: "Eddy", score: 58}, %{name: "Zelda", score: 56}]
]

With Zelda‘s record appearing after Eddy.

Resources

We're building an AI-powered Product Operations Cloud, leveraging AI in almost every aspect of the software delivery lifecycle. Want to test drive it with us? Join the ProdOps party at ProdOps.ai.