2010-08-27 61 views
7

如果我想交錯的一組中的Ruby陣列,每個陣列是相同的長度,我們可以這樣做的:如何交織不同長度的陣列,紅寶石

a.zip(b).zip(c).flatten 

然而,我們如何解決這個問題,如果陣列可以是不同的大小?

我們可以這樣做:

def interleave(*args) 
    raise 'No arrays to interleave' if args.empty? 
    max_length = args.inject(0) { |length, elem| length = [length, elem.length].max } 
    output = Array.new 
    for i in 0...max_length 
    args.each { |elem| 
     output << elem[i] if i < elem.length 
    } 
    end 
    return output 
end 

但有一個更好的「紅寶石」的方式,可能使用zip或調換或一些這樣?

回答

7

如果源數組沒有在他們nil,你只需要第一陣列nil S,拉鍊會自動墊的其他擴展與nil。這也意味着你使用compact清潔額外的條目出這是希望比顯式循環

def interleave(a,*args) 
    max_length = args.map(&:size).max 
    padding = [nil]*[max_length-a.size, 0].max 
    (a+padding).zip(*args).flatten.compact 
end 

下面是如果陣列做的工作稍微複雜一點的版本包含nil

def interleave(*args) 
    max_length = args.map(&:size).max 
    pad = Object.new() 
    args = args.map{|a| a.dup.fill(pad,(a.size...max_length))} 
    ([pad]*max_length).zip(*args).flatten-[pad] 
end 
更有效
5

您的實施對我來說看起來不錯。你可能實現這個使用#zip通過填充一些垃圾值的數組,壓縮他們,然後展平和刪除垃圾。但是這太令人費解的國際海事組織。你在這裏乾淨,自我解釋,只需要被磨光。

編輯:修正了booboo。

def interleave(*args) 
    raise 'No arrays to interleave' if args.empty? 
    max_length = args.map(&:size).max 
    output = [] 
    max_length.times do |i| 
    args.each do |elem| 
     output << elem[i] if i < elem.length 
    end 
    end 
    output 
end 

a = [*1..5] 
# => [1, 2, 3, 4, 5] 
b = [*6..15] 
# => [6, 7, 8, 9, 10, 11, 12, 13, 14, 15] 
c = [*16..18] 
# => [16, 17, 18] 

interleave(a,b,c) 
# => [1, 6, 16, 2, 7, 17, 3, 8, 18, 4, 9, 5, 10, 11, 12, 13, 14, 15] 

編輯:爲了好玩

def interleave(*args) 
    raise 'No arrays to interleave' if args.empty? 
    max_length = args.map(&:size).max 
    # assumes no values coming in will contain nil. using dup because fill mutates 
    args.map{|e| e.dup.fill(nil, e.size...max_length)}.inject(:zip).flatten.compact 
end 

interleave(a,b,c) 
# => [1, 6, 16, 2, 7, 17, 3, 8, 18, 4, 9, 5, 10, 11, 12, 13, 14, 15] 
+0

謝謝,沒有考慮args.map(:大小)。事實上,我以前從未見過這種方法。 max_length.times比我的for循環更清潔。 – ChrisInEdmonton 2010-08-27 20:55:36

+0

我曾想過用nil填充較短的數組,然後將它們交錯,然後壓縮nils。這很好,當且僅當你可以確定你的源數組中沒有任何nil。 :) – ChrisInEdmonton 2010-08-27 21:07:33

6

這是一個更簡單的方法。這需要你通過陣列zip訂單的優勢:

def interleave(a, b) 
    if a.length >= b.length 
    a.zip(b) 
    else 
    b.zip(a).map(&:reverse) 
    end.flatten.compact 
end 

interleave([21, 22], [31, 32, 33]) 
# => [21, 31, 22, 32, 33] 

interleave([31, 32, 33], [21, 22]) 
# => [31, 21, 32, 22, 33] 

interleave([], [21, 22]) 
# => [21, 22] 

interleave([], []) 
# => [] 

被警告:這將刪除所有nil的:

interleave([11], [41, 42, 43, 44, nil]) 
# => [11, 41, 42, 43, 44]