Skip to content

Instantly share code, notes, and snippets.

@hildersantos
Created March 1, 2018 04:59
Show Gist options
  • Save hildersantos/0c41d5c1f2f0e99f1dd97eb5d7934a08 to your computer and use it in GitHub Desktop.
Save hildersantos/0c41d5c1f2f0e99f1dd97eb5d7934a08 to your computer and use it in GitHub Desktop.
List (Array) Flattener in Elixir
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
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