如何从数组中提取子数组和其余元素作为数组?

时间:2015-05-13 12:24:44

标签: arrays ruby

让我们说我有一个数组数组

aoa = [1, 2, [3, 4], 5, [6, 7, 8], 9]

我想将数组和单个元素提取为数组,如下所示

[[1,2,5,9],[3,4],[6,7,8]] #=>order is not important

我试过这个,但不知道如何处理个别元素

aoa.map{|i|  i if i.kind_of?(Array)}.compact #=> [[3, 4], [6, 7, 8]] 

5 个答案:

答案 0 :(得分:7)

您可以使用分区(和@CarySwoveland指向的splat运算符) a,i = aoa.partition {| i | i.is_a?数组} #=> [[[3,4],[6,7,8]],[1,2,5,9]] [* a,i] #=> [[3,4],[6,7,8],[1,2,5,9]]

答案 1 :(得分:4)

Enumerable#group_by返回Hash,其值为您想要的值:

aoa.group_by(&:size).values.map(&:flatten)
# => [[1, 2, 5, 9], [3, 4], [6, 7, 8]]

@Cary Swoveland指出使用size进行分组是一个坏主意,因为与Fixnum#size大小相同的子数组会导致意外结果。应该使用group_by(&:class)代替。

答案 2 :(得分:2)

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]]

答案 3 :(得分:2)

以下是其他三种方式:

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

为@ Doguita使用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]]

如果aoa仅包含数组,该怎么办?

如果aoa的所有元素都是数组,则所有这些方法都将返回包含空数组的数组。如果不需要空数组,请将.reject(&:empty?)添加到最后。例如:

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]]

您可以使用reject!,但如果您这样做,请避免陷阱!

您可以将reject(&:empty?)替换为效率更高的reject!(&:empty?),但如果您这样做,请记住,如果没有更改,reject!会返回nil,所以你需要写:

 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]]

答案 4 :(得分:1)

 >   aoa.inject([[]]) {|temp, x| x.is_a?(Array) ? temp << x : (temp.first << x); temp }
 #=> [[1, 2, 5, 9], [3, 4], [6, 7, 8]]