How do I extract the sub arrays and the rest of the array elements from the array?
Let's say I have an array of arrays
aoa = [1, 2, [3, 4], 5, [6, 7, 8], 9]
I want to extract arrays and single items as an array as shown below
[[1,2,5,9],[3,4],[6,7,8]] #=>order is not important
I tried this but not sure how to handle the individual items
aoa.map{|i| i if i.kind_of?(Array)}.compact #=> [[3, 4], [6, 7, 8]]
You can use partition (and operator splat
as @CarySwoveland pointed out)
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]]
Enumerable#group_by
returns Hash
which values 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
for grouping is a bad idea, because subarrays with the same size Fixnum#size
will cause unexpected results. group_by(&:class)
should be used instead.
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]]
There are three other ways:
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 using @Doguita Enum # section :
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
only contains arrays?
All of these methods return an array containing an empty array if all elements aoa
are arrays. If you don't want an empty array, press all the way .reject(&:empty?)
. 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 use instead reject!
, but if you do, avoid the trap!
You can replace reject(&:empty?)
with reject!(&:empty?)
, which is a little more efficient, but if you do, remember what it reject!
returns nil
if no changes are 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]]
> aoa.inject([[]]) {|temp, x| x.is_a?(Array) ? temp << x : (temp.first << x); temp }
#=> [[1, 2, 5, 9], [3, 4], [6, 7, 8]]