Created
March 1, 2018 04:59
-
-
Save hildersantos/0c41d5c1f2f0e99f1dd97eb5d7934a08 to your computer and use it in GitHub Desktop.
List (Array) Flattener in Elixir
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
defmodule ArrayFlattener do | |
@moduledoc """ | |
This module is used to flatten nested array/lists. | |
""" | |
@doc ~S""" | |
This function is used to flatten nested lists. | |
Usage: | |
iex> ArrayFlattener.flatten([1, [2, 3], [4, 5, 6]]) | |
[1, 2, 3, 4, 5, 6] | |
iex> ArrayFlattener.flatten(:wrongargument) | |
** (ArgumentError) Unrecognized input: argument should be a list | |
array_flattener.exs:8: ArrayFlattener.flatten/1 | |
""" | |
def flatten(list) when is_list(list) do | |
do_flatten(list, []) | |
|> Enum.reverse() # Reverse is necessary because of recursion. List concatenation is VERY expensive, so it's better to do reversion. | |
end | |
def flatten(_) do | |
raise(ArgumentError, message: "Unrecognized input: argument should be a list") | |
end | |
# Collection of private functions for list recursion. | |
# If a list `head` is an empty list (i.e. passed through recursion) | |
defp do_flatten([h | t], acc) when h == [] do | |
do_flatten(t, acc) | |
end | |
# If the `head` is actually a list, we shall flatten it | |
defp do_flatten([h | t], acc) when is_list(h) do | |
do_flatten(t, do_flatten(h, acc)) | |
end | |
# Everything ok? Flat list? Let's go on basic recursion | |
defp do_flatten([h | t], acc) do | |
do_flatten(t, [h | acc]) | |
end | |
# Empty recursion? Return the results to `ArrayFlattener.flatten/1` | |
defp do_flatten([], acc) do | |
acc | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
ExUnit.start() | |
defmodule ArrayFlattenerTest do | |
# Require `ArrayFlattener` module, as it is a standalone test, not using `mix` (assuming it is on the same directory as the test file) | |
Code.require_file("array_flattener.exs", __DIR__) | |
use ExUnit.Case, async: true | |
test "returns a flattened list with correct input" do | |
assert ArrayFlattener.flatten([1, [2, [3, 4, [5, 6]]]]) === [1,2,3,4,5,6] | |
end | |
test "raises on incorrect input" do | |
assert_raise ArgumentError, "Unrecognized input: argument should be a list", fn -> | |
ArrayFlattener.flatten("incorrect") | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment