Loop through a list of values, find matches in keys and sum matched values in Elixir

Advertisements

I’m learning Elixir and I’m having a difficulty with this simple problem:

I have a list of values:

my_list = ["a", "b", "c", "y", "z", "a", "e"]

And I have a map:

my_map = %{"a" => -1, "b" => 0, "c" => 1, "d" => 2, "e" => 3}

I want to loop through my_list, find all key occurrences in my_map and sum the values from my_map if the occurrence happened.

In the above example it should return 2 because:

-1 + 0 + 1 + (ignored) + (ignored) - 1 + 3

# => 2

This is a very easy thing to do in languages with mutable variables (we can loop the list and add a counter). I’m working on changing my mindset.

Thank you for help!

>Solution :

I’m working on changing my mindset.

Admirable. You’ll find great success in Elixir if you’re willing to change your mindset and try to think more functionally. With that in mind, let’s break the problem down.

I want to loop through my_list

More precisely, you want to do something to each element of the list and get a list of the results. That’s Enum.map/2.

Enum.map(my_list, fn x -> ...)

Now, ... needs to be replaced with what we want to do to each list element. We want to get the corresponding map elements, ignoring those that are not present. Since we’re taking a sum, "ignoring" really just means "replacing with zero". Map.get/3 can get a value from a map, using a default if not provided.

Enum.map(my_list, fn x -> Map.get(my_map, x, 0) end)

Now, we have a list of numbers. We just want the sum. That could be done in terms of Enum.reduce/3, but summing is a common enough task that it has its own function: Enum.sum/1.

Enum.sum(Enum.map(my_list, fn x -> Map.get(my_map, x, 0) end))

Finally, this reads backwards. It says "sum the result of mapping over the list", when it would read much cleaner as "take the list, get the elements from the map, then take a sum". We can clean it up with the pipe operator. The following is equivalent to the above.

my_list |> Enum.map(fn x -> Map.get(my_map, x, 0) end) |> Enum.sum

Leave a ReplyCancel reply