Héctor
Héctor

Reputation: 26034

Compare and reduce pairs in two lists

Given Alice's triplet and Bob's triplet (lists), I need to compare each element so if alice_triplet[i] > bob_triplet[i], Alice's score is incremented by one, and vice versa.

I have this code:

def main do
    alice_triplet = [5, 6, 7]
    bob_triplet = [3, 6, 10]

    alice_score = 0
    bob_score = 0

    Enum.zip(alice_triplet, bob_triplet) 
    |> Enum.each(fn 
        tuple when elem(tuple, 0) > elem(tuple, 1) -> alice_score = alice_score + 1
        tuple when elem(tuple, 1) > elem(tuple, 0) -> bob_score = bob_score + 1
        _ -> nil end)

    IO.puts alice_score
    IO.puts bob_score

end

But, the output is:

0
0

Why? I think it is about the variable scope because I'm getting this warning:

warning: variable "alice_score" is unused solution.ex:12

warning: variable "bob_score" is unused solution.ex:13

Is there a "more functional" way to do this? I'm learning Elixir (and FP in general, actually), so any advice will be appreciated.

Upvotes: 1

Views: 352

Answers (1)

Dogbert
Dogbert

Reputation: 222090

The statement alice_score = alice_score + 1 does not modify the outer alice_score, it creates a new local alice_score with the value set to the outer value + 1. This has been covered in many answers. The solution almost always is to use Enum.reduce/3 with the state you need to change used as the accumulator.

Here's how that can be applied to your code:

alice_triplet = [5, 6, 7]
bob_triplet = [3, 6, 10]

{alice_score, bob_score} = Enum.zip(alice_triplet, bob_triplet) |>
Enum.reduce({0, 0}, fn 
  tuple, {as, bs} when elem(tuple, 0) > elem(tuple, 1) -> {as + 1, bs} 
  tuple, {as, bs} when elem(tuple, 1) > elem(tuple, 0) -> {as, bs + 1}
  _, {as, bs}  -> {as, bs}
end)

IO.puts alice_score
IO.puts bob_score

You can also simplify the code using pattern matching instead of elem/2 (elem/2 is rarely used in idiomatic Elixir code):

alice_triplet = [5, 6, 7]
bob_triplet = [3, 6, 10]

{alice_score, bob_score} = Enum.zip(alice_triplet, bob_triplet) |> 
Enum.reduce({0, 0}, fn 
  {a, b}, {as, bs} when a > b -> {as + 1, bs}
  {a, b}, {as, bs} when b > a -> {as, bs + 1}
  _, {as, bs}  -> {as, bs}
end)

IO.puts alice_score
IO.puts bob_score

The output in both cases is

1
1

Upvotes: 3

Related Questions