I have an Enum of maps and when a map has a category, that should be the category for the next maps, until I find another map that has a new category.
Let me explain it better with an example.
[ %{"category" => "FIRST CATEGORY", "code" => 0}, %{ "code" => 34, "name" => "jack" }, %{ "code" => 22, "name" => "mary" }, %{"category" => "SECOND CATEGORY", "code" => 0}, %{ "code" => 1023, "name" => "john" }, %{ "code" => 135, "name" => "lucy" }, %{ "code" => 2, "name" => "leonard" }, ]
Into this:
[ %{ "category" => "FIRST CATEGORY", "code" => 34, "name" => "jack" }, %{ "category" => "FIRST CATEGORY", "code" => 22, "name" => "mary" }, %{ "category" => "SECOND CATEGORY", "code" => 1023, "name" => "john" }, %{ "category" => "SECOND CATEGORY", "code" => 135, "name" => "lucy" }, %{ "category" => "SECOND CATEGORY", "code" => 2, "name" => "leonard" }, ]
Iād use Enum.reduce
with your current category and output as the accumulators. Something like (untested):
{output, _last_category} = Enum.reduce(input, {[], nil}, fn item, {acc, current_category} -> case item["category"] do nil -> {[%{category: current_category, code: item["code"], name: item["name"]} | acc], current_category} value -> {acc, value} end end Enum.reverse(output)
2 Likes
Here are two other versions in you case you like.
- Using recursion:
defmodule Category do def merge(list), do: merge(list, [], nil) def merge([], output, _category), do: Enum.reverse(output) def merge([%{"category" => category} | tail], output, _category), do: merge(tail, output, category) def merge([head | tail], output, category), do: merge(tail, [Map.put(head, "category", category) | output], category) end
- Using Enum.reduce/3. Slightly different from previous response.
list |> Enum.reduce({nil, []}, fn %{"category" => category}, {_category, output} -> {category, output} item, {category, output} -> {category, [Map.put(item, "category", category) | output]} end) |> elem(1) |> Enum.reverse()
1 Like