Reputation: 690
In my ruby project, I have an array of arrays of arrays which is the result of doing some heavy graph traversal
example:
[[], [1, 2, 3, 4, 5], [[], [], [[], [], [34, 54, 23, 45]]]]
I want the final product to be
[[1, 2, 3, 4, 5], [34, 54, 23, 45]]
flatten will leave me with
[1, 2, 3, 4, 5, 34, 54, 23, 45]
so I don't want that
I'm stuck and could use some help on how to do this
so far, I have
class Array
def flatten_blanks
each{ |elem| elem.flatten_blanks if elem.is_a?(Array) }
reject!{ |elem| elem.is_a?(Array) && elem.length < 1 }
self
end
end
which is close but leaves me with something like
[[[[[[[1, 2, 3, 4, 5]]]]]]], [[[[[[[34, 54, 23, 45]]]]]]]
Upvotes: 1
Views: 2031
Reputation: 192
Let's call your array arr
arr.map(&:flatten).reject(&:empty?)
To explain a little, you run flatten on the array's elements instead of the array itself, and then delete the empty subarrays.
Upvotes: 2
Reputation: 110675
require 'json'
arr = [[], [1, 2, 3, 4, 5], [[], [], [[], [], [34, 54, 23, 45]]]]
JSON.parse("[#{arr.to_json.scan(/\[[^\[\]]+\]/).join(',')}]")
#=> [[1, 2, 3, 4, 5], [34, 54, 23, 45]]
A recursive method (similar to mudsie's recursive proc) could also be used.
def recurse(arr)
arr.each_with_object([]) { |e,a|
e.first.is_a?(Array) ? a.concat(recurse e) : a << e unless e.empty? }
end
recurse(arr)
#=> [[1, 2, 3, 4, 5], [34, 54, 23, 45]]
Upvotes: 2
Reputation: 121000
squeeze = -> (arr, acc = []) do
case arr.compact.first
when NilClass then acc
when Array
arr.reject(&:empty?).map { |e| squeeze.(e, acc) }.first
else acc << arr
end
end
squeeze.(arr)
#⇒ [[1, 2, 3, 4, 5], [34, 54, 23, 45]]
Upvotes: 9
Reputation: 2543
For you example it does the trick:
array = [[], [1, 2, 3, 4, 5], [[], [], [[], [], [34, 54, 23, 45]]]]
array.map(&:flatten).delete_if(&:empty?)
It will produce:
[[1, 2, 3, 4, 5], [34, 54, 23, 45]]
Upvotes: 2