假设我有一个数组的数组
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]]
您可以使用partition(以及由@CarySwoveland指出的splat
运算符)。
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
返回一个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)
代替。
.map(&:flatten)
来满足问题所需的格式。 - Andrey Deinekogroup_by(&:class)
。 - Yevgeniy Anfilofyev[[1, 2], [1, 2, 3, 4, 5, 6, 7, 8]]
吗? - Yu Hao1.size #=> 8; 2.size #=> 8; [1,2,3,4,5,6,7,8].size #=> 8
,这就是我测试后得到的结果。Fixnum.size
返回字节数;Array#size
返回元素数量。 - Cary Swovelandnested_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]]
nested_a = aoa.each_with_object([[]]) { |e,arr|...
。另外,我建议你删除最后一行(注释)中的 #
,以提醒读者那里需要 nested_a
。 - Cary Swovelandaoa = [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]]
> aoa.inject([[]]) {|temp, x| x.is_a?(Array) ? temp << x : (temp.first << x); temp }
#=> [[1, 2, 5, 9], [3, 4], [6, 7, 8]]
aoa
包含除整数和数组之外的元素怎么办?最好写成!i.is_a?(Array)
。我认为在这里使用partition
是正确的方法,我认为这就是读者喜欢您的答案的原因。您的“编辑”是一个干扰因素。我会删除它,并添加额外的步骤来修改partition
返回的数组。 - Cary Swoveland