Local accumulators for cleaner comprehensions

Since you’ve closed the previous discussion and my library was kinda mentioned there, here is the solution with Iteraptor.

Mix.install([:iteraptor])

Iteraptor.map_reduce(input, %{lesson: 1, top: 1}, fn
    {k, %{"reset_lesson_position" => reset?} = v}, counters ->
        {{k, Map.put(v, "position", counters.top)},
            %{top: counters.top + 1, lesson: if(reset?, do: 1, else: counters.lesson)}}
    {[_, "lessons", _] = k, v}, counters ->
        {{k, Map.put(v, "position", counters.lesson)}, %{counters | lesson: counters.lesson + 1}}
    {k, v}, counters ->
        {{k, v}, counters}
end, yield: :all)

Please note, that this solution might be easily extended to be generic, i. e. not dependent on any depth/parameter name save for the one resetting positions.


I’m not advocating the use of iteraptor though :slight_smile: It has its flaws. I indeed advocate a Kernel.update_reduce_in/3, accepting the function of arity 2 as the third parameter. It won’t solve the issue out of the box, but one get_in/2 in advance and Enum.zip/2ing the outcome to the input would do (and the complexity would not change even though we are to iterate the list twice.)

7 Likes