In the absence of a product manager, I assumed either use case could happen:
- a reasonable number of nested levels in the array (and performance doesn't matter too much).
- an arbitrary number of nested levels in the array.
In this approach, a simple solution using standard recursion is appropriate
(#flatten1
). The solution is simple to understand and is very maintainable.
In this approach, I used tail recursion (which is equivalent to a for loop). See
#flatten2
Unfortunately, as will be made clear below, the tail recursive
solution requires that you manually re-create the stack---hence, it can handle
more complex arrays (than #flatten1
) at the cost of potentially being
bogged down by the GC.
The idea is that the array is a tree. Integers are leaves and child arrays are
nodes. In order to "flatten" the array, all you need to do is a depth-first
traversal of the tree representation---at each leaf adding its value to a
result
array.
Unfortunately, because the array is not a tree you either need to:
- pre-convert the array into a tree (this can be done in linear time, using linear memory). OR
- convert items into "nodes" dynamically (as
#flatten2
does).
Approach 1 potentially runs out of memory.
Approach 2 can handle larger, more complex arrays. However, you need to keep track of parent nodes, and so memory can still be a problem. Also, because objects get recycled, the GC can also be an issue.
Run unit tests
gradle test
Run speed tests
gradle speedTests
Start with the README.
Code is in
flatten1.kt
andflatten2.kt
.Tests start with
system
andtest
.Best way to run this code is by cloning this gist and either running
gradle speedTests
orgradle test
.