Skip to content

Instantly share code, notes, and snippets.

@graimon
Created January 18, 2020 11:46
Show Gist options
  • Select an option

  • Save graimon/06bf30f248c86f956c985f56bc19475c to your computer and use it in GitHub Desktop.

Select an option

Save graimon/06bf30f248c86f956c985f56bc19475c to your computer and use it in GitHub Desktop.
Flatten Exercise for Theorem

Theorem Exercise

Write some code, that will flatten an array of arbitrarily nested arrays of integers into a flat array of integers. e.g. [[1,2,[3]],4] -> [1,2,3,4].

Solution

Excercise::Flattener is a class with a flatten function, that takes care of solving the exercise.

Installation

You need to have Ruby installed, as well as the bundler gem.

Then run:

bundle install

Run tests

To run the test use: rspec flattener_spec.rb

Comments

The project folder structure would change (similar to a gem layout) if it wasn't for the gist limitations.

There is not much to comment about the solution, a recursive function checking that the arguments match the prerequisites and raising exceptions if they are not. I decided to use Array.reduce in favor of readability, code length and finally performance.

module Exercise
class Flattener
def flatten(array)
raise ArgumentError, 'argument should be an Array' unless array.is_a? Array
_flatten(array)
end
private
def _flatten(array_or_integer)
array_or_integer.reduce([]) do |memo, element|
unless [Array, Integer].any? { |klass| element.is_a?(klass) }
raise ArgumentError, 'array elements should be either Arrays or Integers'
end
if element.is_a?(Array)
memo + _flatten(element) #concat
else
memo << element #push
end
end
end
# one liner version
# array_or_integer.reduce([]) { |memo, i| i.is_a?(Array) ? memo + _flatten(i) : memo << i}
end
end
require './flattener'
describe Exercise::Flattener do
let(:flattener) { described_class.new }
it 'flattens arrays with several levels of nested arrays' do
array1 = [1, 2, 3]
expect(flattener.flatten(array1)).to eq(array1.flatten)
array2 = [1, [2], 3]
expect(flattener.flatten(array2)).to eq(array2.flatten)
array3 = [1, 2, [3 , 4, [5, 6]]]
expect(flattener.flatten(array3)).to eq(array3.flatten)
array4 = [1, 2, [3 , 4, [5, [[6], 7, 8]]]]
expect(flattener.flatten(array4)).to eq(array4.flatten)
end
it 'throws ArgumentError' do
invalid_argument1 = ['a', [1, [true]]]
expect{flattener.flatten(invalid_argument1)}.to raise_error(ArgumentError)
invalid_argument2 = 1
expect{flattener.flatten(invalid_argument2)}.to raise_error(ArgumentError)
end
end
source "https://rubygems.org"
group :test do
gem "rspec"
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment