Skip to content

Instantly share code, notes, and snippets.

@amiralles
Last active October 3, 2018 14:59
Show Gist options
  • Save amiralles/ec5333f886f9e3f76bfbf6b25568ba03 to your computer and use it in GitHub Desktop.
Save amiralles/ec5333f886f9e3f76bfbf6b25568ba03 to your computer and use it in GitHub Desktop.
How to flatten an arbitrary length array without using Array#flatten method.
#!/usr/local/bin/ruby -w
# This module adds to the class that includes it the ability to flatten
# arbitrary nested arrays.
module ArrayFlattener
# This methods flattens an arbitrary nested array.
# It returns a flat array if the input is valid, nil is the input
# is nil, or throws an exception in any other case.
def flatten array, res = Array.new
# Guard against nils.
return nil unless array
# Guard against invalid types.
unless array.is_a?(Array)
die_arg_is_not_array "array", array
end
# If we get this far, array is of type Array, and it's not nil.
# As long as items concerns, there is no need to validate that they
# are of type integer, because that doesn't change the way this
# method works. It can handle ints, strings, airplanes, whatever.
array.each do |e|
if e&.is_a?(Array)
flatten(e).each { |se| res << se }
else
# Plain element or nil. (In this context, nil is fine.)
res << e
end
end
return res
end
def die_arg_is_not_array arg_name, arg_val
raise ArgumentError,
"Argument '#{arg_name}' is of type #{arg_val.class}. We expected Array."
end
end
require 'test/unit'
class FlatteingTest < Test::Unit::TestCase
include ArrayFlattener
# 1. The most basic test case. Given a nested array, return a flattened one.
def test_flatten_singly_nested_array
nested_array = [[1,2,[3]],4]
flat_array = [1,2,3,4]
assert_equal(flat_array, flatten(nested_array))
end
# 2. Flatten a somewhat "deeply" nested array.
def test_flatten_deeply_nested_array
nested_array = [[1,2,[3,[4,5]]],6]
flat_array = [1,2,3,4,5,6]
assert_equal(flat_array, flatten(nested_array))
end
# 3. Nested empty array.
def test_flatten_a_nested_empty_array
nested_array = [[]]
flat_array = []
assert_equal(flat_array, flatten(nested_array))
end
# 4. Protect against nils arrays.
def test_flatten_a_nil_array
# The way this method works, is: given a nil input, we must expect
# a nil output.
nested_array = nil
flat_array = nil
assert_equal(flat_array, flatten(nested_array))
end
# 5. Protect against nil elements.
def test_flatten_nested_array_that_contains_nil_elements
# nil elements are ok. If the array contains a nil element, that
# elements get copied as if it was an integer.
nested_array = [[1,2,[3,[4,nil]]],6]
flat_array = [1,2,3,4,nil,6]
assert_equal(flat_array, flatten(nested_array))
assert_equal(flat_array, flatten(nested_array))
end
# 6. Try to flatten and object that is not an array.
def test_throws_when_first_arg_is_not_an_array
errmsg = "Argument 'array' is of type Integer. We expected Array."
assert_raise_message errmsg do
flatten(123)
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment