I would like to do something like join with an Array, but instead of getting the result as a String, I would like to get an Array. I will call this interpolate. For example, given:
a = [1, 2, 3, 4, 5]
I expect:
a.interpolate(0) # => [1, 0, 2, 0, 3, 0, 4, 0, 5]
a.interpolate{Array.new} # => [1, [], 2, [], 3, [], 4, [], 5]
What is the best way to get this? The reason I need it to take a block is because when I use it with a block, I want different instances for each interpolator that comes in between.
After getting great answers from many, I came up with some modified ones.
This one is a modification from tokland’s answer. I made it accept nil for conj1. And also moved if conj2 condition to outside of the flat_map loop to make it faster.
class Array
def interpolate conj1 = nil, &conj2
return [] if empty?
if conj2 then first(length - 1).flat_map{|e| [e, conj2.call]}
else first(length - 1).flat_map{|e| [e, conj1]}
end << last
end
end
This one is a modification of Victor Moroz’s answer. I added the functionality to accept a block.
class Array
def interpolate conj1 = nil, &conj2
return [] if empty?
first, *rest = self
if conj2 then rest.inject([first]) {|a, e| a.push(conj2.call, e)}
else rest.inject([first]) {|a, e| a.push(conj1, e)}
end
end
end
After benchmark test, the second one looks faster. It seems that flat_map, although looking beautiful, is slow.
Not really sure what you want to do with a block, but I would do it this way:
UPDATE:
Benchmarks (array size = 100):
Actually I am a bit surprised, I thought
zipwould be faster.UPDATE2:
zipis faster,flattenis not.