Given that the cat is now out of the bag - the variation I had:
defmodule Demo do
defp buy_to_tuple(%{code: code, quantity: qty}),
do: {code, qty}
defp sell_to_tuple(%{code: code, quantity: qty}),
do: {code, -qty}
defp update_qty({code, qty}, map),
do: Map.update(map, code, qty, &(&1 + qty))
defp split_buy_sell({code, qty} = item, {buys, sells} = acc) do
cond do
qty > 0 ->
{[item | buys], sells}
qty < 0 ->
{buys, [{code, -qty} | sells]}
true ->
# ignore 0 qty
acc
end
end
defp tuple_to_map({code,qty}),
do: Map.new([code: code, quantity: qty])
defp to_maps({buys, sells}),
do: {Enum.map(buys, &tuple_to_map/1), Enum.map(sells, &tuple_to_map/1)}
def run(buy, sell) do
buys = Map.new(buy, &buy_to_tuple/1)
sell
|> Enum.map(&sell_to_tuple/1)
|> List.foldl(buys, &update_qty/2)
|> Enum.reduce({[],[]}, &split_buy_sell/2)
|> to_maps()
end
end
sell = [
%{quantity: 3400, code: 915},
%{quantity: 22, code: 9394},
%{quantity: 24, code: 10003},
%{quantity: 22, code: 10013},
%{quantity: 999, code: 999},
%{quantity: 38, code: 1015}
]
buy = [
%{quantity: 40, code: 1001},
%{quantity: 18, code: 933},
%{quantity: 4445, code: 9394},
%{quantity: 1305, code: 915},
%{quantity: 999, code: 999},
%{quantity: 43, code: 8394}
]
{buy, sell} = Demo.run(buy,sell)
IO.puts("#{inspect buy}")
IO.puts("#{inspect sell}")
Alternately:
# $ elixir demo.exs
# [%{code: 9394, quantity: 4423}, %{code: 8394, quantity: 43}, %{code: 1001, quantity: 40}, %{code: 933, quantity: 18}]
# [%{code: 10013, quantity: 22}, %{code: 10003, quantity: 24}, %{code: 1015, quantity: 38}, %{code: 915, quantity: 2095}]
#
defmodule Demo do
defp buy_to_tuple(%{code: code, quantity: qty}),
do: {code, qty}
defp sell_to_tuple(%{code: code, quantity: qty}),
do: {code, -qty}
defp update_qty({code, qty}, map),
do: Map.update(map, code, qty, &(&1 + qty))
defp into_map(buy_or_sell_list, map, convert) do
buy_or_sell_list
|> Enum.map(convert)
|> List.foldl(map, &update_qty/2)
end
defp split_buy_sell({code, qty} = item, {buys, sells} = acc) do
cond do
qty > 0 ->
{[item | buys], sells}
qty < 0 ->
{buys, [{code, -qty} | sells]}
true ->
# ignore 0 qty
acc
end
end
defp tuple_to_map({code, qty}),
do: Map.new(code: code, quantity: qty)
defp to_maps({buys, sells}),
do: {Enum.map(buys, &tuple_to_map/1), Enum.map(sells, &tuple_to_map/1)}
def run(buy_list, sell_list) do
buys = into_map(buy_list, %{}, &buy_to_tuple/1)
sell_list
|> into_map(buys, &sell_to_tuple/1)
|> Enum.reduce({[], []}, &split_buy_sell/2)
|> to_maps()
end
end
sell = [
%{quantity: 2000, code: 915},
%{quantity: 1400, code: 915},
%{quantity: 22, code: 9394},
%{quantity: 24, code: 10003},
%{quantity: 22, code: 10013},
%{quantity: 999, code: 999},
%{quantity: 38, code: 1015}
]
buy = [
%{quantity: 40, code: 1001},
%{quantity: 18, code: 933},
%{quantity: 3000, code: 9394},
%{quantity: 1445, code: 9394},
%{quantity: 1305, code: 915},
%{quantity: 999, code: 999},
%{quantity: 43, code: 8394}
]
{buy, sell} = Demo.run(buy, sell)
IO.puts("#{inspect(buy)}")
IO.puts("#{inspect(sell)}")