Last active
October 3, 2018 14:59
-
-
Save amiralles/ec5333f886f9e3f76bfbf6b25568ba03 to your computer and use it in GitHub Desktop.
How to flatten an arbitrary length array without using Array#flatten method.
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
#!/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