2010-08-27 27 views
7

farklı uzunlukta diziler serpiştirmek ve her dizi aynı uzunlukta olduğu nasıl biz böylece yapabilirdi diziler farklı boyutlarda olabilir eğer bu sorunu çözmek?Ben Ruby diziler kümesini serpiştirmek istiyorum Ruby

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 

Ama daha iyi bir 'Ruby' yolu vardır belki zip kullanarak veya devrik ya da bazı tür:

Biz böyle bir şey yapabilir?

cevap

7

, yalnızca nil s, zip otomatik ped diğerleri ile ilk dizi genişletmek gerekir nil ile. Bu aynı zamanda açık döngüler

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 
İşte

diziler yaparsanız çalışır biraz daha karmaşık bir sürümü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 
ihtiva edilir

daha umutla daha etkilidir hangi ekstra girdileri temizlemek için compact kullanmak olsun demek
5

Uygulamanız bana iyi görünüyor. , numaralı telefonu kullanarak, #zip kullanarak dizileri bazı çöp değerleriyle doldurup, sıkıştırın, sonra da düzleştirin ve çöpleri çıkarın. Ama bu çok kıvrık IMO. Burada sahip olduğunuz şey temiz ve kendini açıklayıcıdır, sadece yakılması gerekiyor.

Edit: Sabit 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] 

Düzenleme: Kaynak diziler onları nil yoksa eğlence

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

Teşekkür, args.map kabul etmemişti (&: boyut). Aslında, bu yaklaşımı daha önce görmemiştim. Max_length.times, benim for döngüsümden de daha temiz. – ChrisInEdmonton

+0

Ve daha kısa dizileri nils ile doldurmayı, onları serpiştirmeyi ve daha sonra çivileri sıkıştırmayı düşündüm. Bu harika ve eğer kaynak dizilerinizde herhangi bir boşluk olmadığından emin olursanız harika olur. :) – ChrisInEdmonton

6

İşte daha basit bir yaklaşım.

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([], []) 
# => [] 

uyardı: Bu tüm nil 's kaldırır: Size zip diziler geçmesi sırayla yararlanır

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