Reputation: 11244
Let us say I have an array of arrays
aoa = [1, 2, [3, 4], 5, [6, 7, 8], 9]
I want to extract arrays and individual elements as array like below
[[1,2,5,9],[3,4],[6,7,8]] #=>order is not important
I tried this but not sure how to deal with individual elements
aoa.map{|i| i if i.kind_of?(Array)}.compact #=> [[3, 4], [6, 7, 8]]
Upvotes: 3
Views: 407
Reputation: 15703
You can use partition (and the splat
operator, as pointed by @CarySwoveland)
a, i = aoa.partition{ |i| i.is_a? Array }
# => [[[3, 4], [6, 7, 8]], [1, 2, 5, 9]]
[*a, i]
# => [[3, 4], [6, 7, 8], [1, 2, 5, 9]]
Upvotes: 7
Reputation: 96
nested_a = [[]]
aoa.each {|e| e.is_a?(Array) ? nested_a << e : nested_a[0] << e }
#remove 1st nested array if empty(Occurs if there were no individual elements)
nested_a.shift if nested_a[0].empty?
nested_a # => [[1, 2, 5, 9], [3, 4], [6, 7, 8]]
Upvotes: 2
Reputation: 122383
Enumerable#group_by
returns a Hash
, whose values are what you want:
aoa.group_by(&:size).values.map(&:flatten)
# => [[1, 2, 5, 9], [3, 4], [6, 7, 8]]
@Cary Swoveland pointed out that using size
to group is a bad idea, because subarrays with the same size as Fixnum#size
would cause unexpected result. group_by(&:class)
should be used instead.
Upvotes: 4
Reputation: 110675
Here are three other ways, for:
aoa = [1, 'cat', [3, 4], 5, [6, 7, 8], 9]
1
is_array = ->(e) { Array===e }
[aoa.reject(&is_array)].concat(aoa.select(&is_array))
#=> [[1, "cat", 5, 9], [3, 4], [6, 7, 8]]
2
Adding a step to @Doguita's use of Enumerable#partition:
a, e = aoa.partition { |e| Array===e }
[e,*a]
#=> [[1, "cat", 5, 9], [3, 4], [6, 7, 8]]
3
sorted = aoa.sort_by { |e| (Array===e) ? 1 : 0 }
[sorted.shift(aoa.count { |e| !(Array===e) })].concat(sorted)
#=> [[1, "cat", 9, 5], [6, 7, 8], [3, 4]]
What if aoa
contains only arrays?
All of these methods will return an array containing an empty array if all the elements of aoa
are arrays. If an empty array is not desired, tack .reject(&:empty?)
to the end. For example:
aoa = [[3, 4], [6, 7, 8]]
[aoa.reject(&is_array)].concat(aoa.select(&is_array))
#=> [[], [3, 4], [6, 7, 8]]
[aoa.reject(&is_array)].concat(aoa.select(&is_array)).reject(&:empty?)
#=> [[3, 4], [6, 7, 8]]
aoa = [1, 'cat', 5, 9]
[aoa.reject(&is_array)].concat(aoa.select(&is_array))
#=> [[1, "cat", 5, 9]]
[aoa.reject(&is_array)].concat(aoa.select(&is_array)).reject(&:empty?)
#=> [[1, "cat", 5, 9]]
You can instead use reject!
, but if you do, avoid the pitfall!
You can replace reject(&:empty?)
with reject!(&:empty?)
, which is a bit more efficient, but if you do, remember than reject!
returns nil
if no change is made, so you need to write:
aoa = [1, 'cat', 5, 9]
arr = [aoa.reject(&is_array)].concat(aoa.select(&is_array))
#=> [[1, "cat", 5, 9]]
arr.reject!(&:empty?)
#=> nil
arr
#=> [[1, "cat", 5, 9]]
Upvotes: 2
Reputation: 5292
> aoa.inject([[]]) {|temp, x| x.is_a?(Array) ? temp << x : (temp.first << x); temp }
#=> [[1, 2, 5, 9], [3, 4], [6, 7, 8]]
Upvotes: 1