Pedra Filosofal 1
A implementação
defmodule Desafio do
@moduledoc """
Este é o módulo que deverá ser preenchido
com a sua solução.
É permitido criar quantas funções privadas for necessário,
mas a única função pública deverá ser a função `split/2`
que está definida como placeholder abaixo.
"""
@spec split(
lista_de_compras :: [
{item :: String.t(), quantidade :: pos_integer(),
preco_unitario_centavos :: pos_integer()}
],
emails :: [String.t()]
) :: [%{String.t() => non_neg_integer()}]
def split(lista_de_compras, emails) do
emails = Enum.uniq(emails)
valor_total = calculate_total_value(lista_de_compras)
num_emails = length(emails)
valor_por_pessoa = div(valor_total, num_emails)
resto = rem(valor_total, num_emails)
emails
|> Enum.with_index(fn email, idx ->
if idx < resto do
{email, valor_por_pessoa + 1}
else
{email, valor_por_pessoa}
end
end)
|> Map.new()
# emails
# |> Map.new(fn email -> {email, valor_por_pessoa} end)
# |> distribute_rem(emails, resto)
end
defp calculate_total_value(list) do
Enum.reduce(list, 0, fn {_nome, quantidade, valor_unitario}, acc ->
acc + quantidade * valor_unitario
end)
# for {_nome, quantidade, valor_unitario} <- list, reduce: 0 do
# acc ->
# acc + quantidade * valor_unitario
# end
# list
# |> Enum.map(fn {_nome, quantidade, valor_unitario} -> quantidade * valor_unitario end)
# |> Enum.sum()
end
defp distribute_rem(map, _emails, 0), do: map
defp distribute_rem(map, [email | t], resto) do
valor = map[email]
modified_map = Map.put(map, email, valor + 1)
distribute_rem(modified_map, t ++ [email], resto - 1)
end
end
# Aqui faremos alguns testes básicos
import ExUnit.Assertions
# Lista de emails com valores repetidos
emails = ~w(
paulo@email.com
valente@email.com
teste@email.com
valente@email.com
paulo@email.com
valente@email.com
)
# Primeiro, vamos validar os casos em que o valor total é menor ou igual ao número de emails
assert %{"paulo@email.com" => 1, "valente@email.com" => 0, "teste@email.com" => 0} ==
Desafio.split([{"banana", 1, 1}, {"maçã", 0, 10}], emails)
assert %{"paulo@email.com" => 1, "valente@email.com" => 1, "teste@email.com" => 0} ==
Desafio.split([{"banana", 2, 1}, {"maçã", 0, 10}], emails)
assert %{"paulo@email.com" => 1, "valente@email.com" => 1, "teste@email.com" => 1} ==
Desafio.split([{"banana", 1, 1}, {"maçã", 1, 2}], emails)
# Caso em que há mais de um centavo de resto
assert %{"paulo@email.com" => 2, "valente@email.com" => 2, "teste@email.com" => 1} ==
Desafio.split([{"banana", 1, 1}, {"maçã", 1, 2}, {"uva", 2, 1}], emails)
# Teste de erro de arredondamento
assert %{
"1@email.com" => 1,
"2@email.com" => 1,
"3@email.com" => 1,
"4@email.com" => 1,
"5@email.com" => 1,
"6@email.com" => 1,
"7@email.com" => 1,
"8@email.com" => 0,
"9@email.com" => 0,
"10@email.com" => 0,
"11@email.com" => 0
} == Desafio.split([{"banana", 7, 1}], Enum.map(1..11, &"#{&1}@email.com"))