讓我們說我有一個數組的數組如何從數組中提取子數組和其餘元素作爲數組?
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]]
讓我們說我有一個數組的數組如何從數組中提取子數組和其餘元素作爲數組?
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(和splat
運營商,通過@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]]
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)
。
> aoa.inject([[]]) {|temp, x| x.is_a?(Array) ? temp << x : (temp.first << x); temp }
#=> [[1, 2, 5, 9], [3, 4], [6, 7, 8]]
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]]
有趣!你可能會考慮'nested_a = aoa.each_with_object([[]]){| e,arr | ...'。另外,我建議你在最後一行(註釋)中刪除'#',以提醒讀者在那裏需要'nested_a'。 –
這裏有其他三種方式,爲:
aoa = [1, 'cat', [3, 4], 5, [6, 7, 8], 9]
is_array = ->(e) { Array===e }
[aoa.reject(&is_array)].concat(aoa.select(&is_array))
#=> [[1, "cat", 5, 9], [3, 4], [6, 7, 8]]
添加到@步Doguita的使用Enumerable#partition:如果
a, e = aoa.partition { |e| Array===e }
[e,*a]
#=> [[1, "cat", 5, 9], [3, 4], [6, 7, 8]]
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'包含整數和數組以外的元素呢?最好寫'!i.is_a?(Array)'。我認爲'分區'是去這裏的路,我想這就是讀者喜歡你的答案。你的「編輯」是一個分心。我會刪除它並添加額外的步驟來修改'partition'返回的數組。 –
@CarySwoveland同意,但是我離開了數組檢查,因爲問題中的示例僅使用整數。謝謝。 – Doguita