如果我想在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
但是有没有更好的'Ruby'方式,也许使用zip或转置或其他一些?
答案 0 :(得分:7)
如果源数组中没有nil
,您只需要使用nil
扩展第一个数组,zip会自动使用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
答案 1 :(得分:7)
这是一种更简单的方法。它利用了将数组传递给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]
答案 2 :(得分:5)
您的实施对我来说很好。你可以使用#zip来实现这一点,方法是在数组中加入一些垃圾值,压缩它们,然后压平并删除垃圾。但这太复杂了IMO。你在这里所拥有的是清洁和自我解释,它只需要被重新保护。
编辑:修正了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]