diff --git a/lib/list_ops.ex b/lib/list_ops.ex index 3010084..672cdba 100644 --- a/lib/list_ops.ex +++ b/lib/list_ops.ex @@ -1,2 +1,41 @@ defmodule ListOps do + def count(list) do + reduce(list, 0, fn(_x,acc) -> acc + 1 end) + end + + def reverse(list) do + reduce(list, [], fn(x, acc) -> [x | acc] end) + end + + def map(list, mapper) do + list + |> reduce([], fn(x, acc) -> [mapper.(x) | acc] end) + |> reverse + end + + def filter(list, filter_fun) do + reduce(list, [], fn(x, acc) -> + if filter_fun.(x), do: [x | acc], else: acc + end) |> reverse + end + + def append(list, other) do + concat([list, other]) + end + + def concat(list_of_lists) do + reduce(list_of_lists, [], fn(x, acc) -> + reduce(x, acc, fn(y, acc2) -> + [y | acc2] + end) + end) |> reverse + end + + def reduce(list, acc, step_fun) + def reduce([h | tail], acc, step_fun) do + reduce(tail, step_fun.(h,acc), step_fun) + end + def reduce([], acc, _step_fun) do + acc + end end diff --git a/test/list_ops_test.exs b/test/list_ops_test.exs index 99f06ff..db343fa 100644 --- a/test/list_ops_test.exs +++ b/test/list_ops_test.exs @@ -27,85 +27,85 @@ defmodule ListOpsTest do assert ListOps.reverse(Enum.to_list(1..1_000_000)) == Enum.to_list(1_000_000..1) end - # test "map of empty list" do - # assert ListOps.map([], &(&1+1)) == [] - # end - # - # test "map of normal list" do - # assert ListOps.map([1,3,5,7], &(&1+1)) == [2,4,6,8] - # end - # - # test "map of huge list" do - # assert ListOps.map(Enum.to_list(1..1_000_000), &(&1+1)) == - # Enum.to_list(2..1_000_001) - # end - # - # test "filter of empty list" do - # assert ListOps.filter([], &odd?/1) == [] - # end - # - # test "filter of normal list" do - # assert ListOps.filter([1,2,3,4], &odd?/1) == [1,3] - # end - # - # test "filter of huge list" do - # assert ListOps.filter(Enum.to_list(1..1_000_000), &odd?/1) == - # Enum.map(1..500_000, &(&1*2-1)) - # end - # - # test "reduce of empty list" do - # assert ListOps.reduce([], 0, &(&1+&2)) == 0 - # end - # - # test "reduce of normal list" do - # assert ListOps.reduce([1,2,3,4], -3, &(&1+&2)) == 7 - # end - # - # test "reduce of huge list" do - # assert ListOps.reduce(Enum.to_list(1..1_000_000), 0, &(&1+&2)) == - # Enum.reduce(1..1_000_000, 0, &(&1+&2)) - # end - # - # test "reduce with non-commutative function" do - # assert ListOps.reduce([1,2,3,4], 10, fn x, acc -> acc - x end) == 0 - # end - # - # test "append of empty lists" do - # assert ListOps.append([], []) == [] - # end - # - # test "append of empty and non-empty list" do - # assert ListOps.append([], [1,2,3,4]) == [1,2,3,4] - # end - # - # test "append of non-empty and empty list" do - # assert ListOps.append([1,2,3,4], []) == [1,2,3,4] - # end - # - # test "append of non-empty lists" do - # assert ListOps.append([1,2,3], [4,5]) == [1,2,3,4,5] - # end - # - # test "append of huge lists" do - # assert ListOps.append(Enum.to_list(1..1_000_000), Enum.to_list(1_000_001..2_000_000)) == - # Enum.to_list(1..2_000_000) - # end - # - # test "concat of empty list of lists" do - # assert ListOps.concat([]) == [] - # end - # - # test "concat of normal list of lists" do - # assert ListOps.concat([[1,2],[3],[],[4,5,6]]) == [1,2,3,4,5,6] - # end - # - # test "concat of huge list of small lists" do - # assert ListOps.concat(Enum.map(1..1_000_000, &[&1])) == - # Enum.to_list(1..1_000_000) - # end - # - # test "concat of small list of huge lists" do - # assert ListOps.concat(Enum.map(0..9, &Enum.to_list((&1*100_000+1)..((&1+1)*100_000)))) == - # Enum.to_list(1..1_000_000) - # end + test "map of empty list" do + assert ListOps.map([], &(&1+1)) == [] + end + + test "map of normal list" do + assert ListOps.map([1,3,5,7], &(&1+1)) == [2,4,6,8] + end + + test "map of huge list" do + assert ListOps.map(Enum.to_list(1..1_000_000), &(&1+1)) == + Enum.to_list(2..1_000_001) + end + + test "filter of empty list" do + assert ListOps.filter([], &odd?/1) == [] + end + + test "filter of normal list" do + assert ListOps.filter([1,2,3,4], &odd?/1) == [1,3] + end + + test "filter of huge list" do + assert ListOps.filter(Enum.to_list(1..1_000_000), &odd?/1) == + Enum.map(1..500_000, &(&1*2-1)) + end + + test "reduce of empty list" do + assert ListOps.reduce([], 0, &(&1+&2)) == 0 + end + + test "reduce of normal list" do + assert ListOps.reduce([1,2,3,4], -3, &(&1+&2)) == 7 + end + + test "reduce of huge list" do + assert ListOps.reduce(Enum.to_list(1..1_000_000), 0, &(&1+&2)) == + Enum.reduce(1..1_000_000, 0, &(&1+&2)) + end + + test "reduce with non-commutative function" do + assert ListOps.reduce([1,2,3,4], 10, fn x, acc -> acc - x end) == 0 + end + + test "append of empty lists" do + assert ListOps.append([], []) == [] + end + + test "append of empty and non-empty list" do + assert ListOps.append([], [1,2,3,4]) == [1,2,3,4] + end + + test "append of non-empty and empty list" do + assert ListOps.append([1,2,3,4], []) == [1,2,3,4] + end + + test "append of non-empty lists" do + assert ListOps.append([1,2,3], [4,5]) == [1,2,3,4,5] + end + + test "append of huge lists" do + assert ListOps.append(Enum.to_list(1..1_000_000), Enum.to_list(1_000_001..2_000_000)) == + Enum.to_list(1..2_000_000) + end + + test "concat of empty list of lists" do + assert ListOps.concat([]) == [] + end + + test "concat of normal list of lists" do + assert ListOps.concat([[1,2],[3],[],[4,5,6]]) == [1,2,3,4,5,6] + end + + test "concat of huge list of small lists" do + assert ListOps.concat(Enum.map(1..1_000_000, &[&1])) == + Enum.to_list(1..1_000_000) + end + + test "concat of small list of huge lists" do + assert ListOps.concat(Enum.map(0..9, &Enum.to_list((&1*100_000+1)..((&1+1)*100_000)))) == + Enum.to_list(1..1_000_000) + end end