2010-08-27 9 views
7

में अलग लंबाई की सरणियों बिछा कैसे मैं रूबी में सरणियों का एक सेट बिछा चाहते हैं, और प्रत्येक सरणी में एक ही लंबाई था, हम क्या कर सकता है तो के रूप में:रूबी

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 

लेकिन वहाँ एक बेहतर 'रूबी' तरीका है, शायद ज़िप का उपयोग कर या स्थानांतरित करता है या कुछ इस तरह:

हम की तरह कुछ कर सकता है?

उत्तर

7

के लिए स्रोत सरणियों उन में nil की जरूरत नहीं है, तो आप केवल nil रों, ज़िप स्वचालित रूप से पैड अन्य लोगों के साथ पहली सरणी का विस्तार करने की जरूरत है nil के साथ। यह भी तुम बाहर जो स्पष्ट छोरों

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 
शामिल है से उम्मीद है कि और अधिक कुशल है compact उपयोग करने के लिए अतिरिक्त प्रविष्टियों को साफ करने के लिए मिल का मतलब
5

आपका कार्यान्वयन मेरे लिए अच्छा लग रहा है। आप कुछ कचरा मूल्य के साथ सरणी भरकर #zip का उपयोग करके इसे प्राप्त कर सकते हैं, उन्हें ज़िप कर सकते हैं, फिर कचरा और कचरा हटा सकते हैं। लेकिन यह बहुत ही मजबूत आईएमओ है। आपके पास यहां क्या है स्वच्छ और आत्म व्याख्यात्मक है, इसे सिर्फ रूबीफाइड होना चाहिए।

संपादित करें: बोबू को फिक्स्ड करें।

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 भी मेरे फॉर-लूप से क्लीनर है। – ChrisInEdmonton

+0

और मैंने निल्स के साथ छोटे सरणी को पैडिंग करने, उन्हें अंतःस्थापित करने, फिर नाइल्स को कॉम्पैक्ट करने के बारे में सोचा था। यह बहुत अच्छा है और केवल तभी यदि आप सुनिश्चित कर सकते हैं कि आपके स्रोत सरणी में उनमें कोई नील नहीं है। :) – ChrisInEdmonton

6

यहां एक आसान तरीका है।

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 की: यह आदेश है कि आप zip को सरणियों पारित का लाभ लेता है

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