我想使用join
执行Array
之类的操作,但我不想将结果作为String
,而是希望得到Array
。我会称之为interpolate
。例如,给定:
a = [1, 2, 3, 4, 5]
我期待:
a.interpolate(0) # => [1, 0, 2, 0, 3, 0, 4, 0, 5]
a.interpolate{Array.new} # => [1, [], 2, [], 3, [], 4, [], 5]
获得此功能的最佳方式是什么?我需要它来阻止块的原因是因为当我将它与块一起使用时,我希望每个插值器都有不同的实例。
在得到许多人的答案后,我想出了一些经过修改的答案。
这是对tokland答案的修改。我接受了nil
conj1
。并且还将if conj2
条件移至flat_map
循环之外以使其更快。
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
这是对Victor Moroz答案的修改。我添加了接受块的功能。
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
基准测试后,第二个看起来更快。似乎flat_map
虽然看起来很漂亮,但速度很慢。
答案 0 :(得分:6)
使用zip:
a.zip(Array.new(a.size) { 0 }).flatten(1)[0...-1]
答案 1 :(得分:3)
另一种方式
class Array
def interpolate(pol=nil)
new_ary = self.inject([]) do |memo, orig_item|
pol = yield if block_given?
memo += [orig_item, pol]
end
new_ary.pop
new_ary
end
end
[1,2,3].interpolate("A")
#=> [1, "A", 2, "A", 3]
[1,2,3].interpolate {Array.new}
#=> [1, [], 2, [], 3]
答案 2 :(得分:2)
class Array
def interpolate_with val
res = []
self.each_with_index do |el, idx|
res << val unless idx == 0
res << el
end
res
end
end
用法:
ruby-1.9.3-p0 :021 > [1,2,3].interpolate_with 0
=> [1, 0, 2, 0, 3]
ruby-1.9.3-p0 :022 > [1,2,3].interpolate_with []
=> [1, [], 2, [], 3]
答案 3 :(得分:1)
不确定你想用块做什么,但我会这样做:
class Array
def interpolate(sep)
h, *t = self
t.empty? ? [h] : t.inject([h]) { |a, e| a.push(sep, e) }
end
end
<强>更新强>
基准(数组大小= 100):
user system total real
inject 0.730000 0.000000 0.730000 ( 0.767565)
zip 1.030000 0.000000 1.030000 ( 1.034664)
实际上我有点惊讶,我认为zip
会更快。
<强> UPDATE2:强>
zip
速度更快,flatten
不是。
答案 4 :(得分:1)
有很多方法可以做到这一点。例如(Ruby 1.9):
class Array
def intersperse(item = nil)
return clone if self.empty?
take(self.length - 1).flat_map do |x|
[x, item || yield]
end + [self.last]
end
end
p [].intersperse(0)
#=> []
p [1, 2, 3, 4, 5].intersperse(0)
#= >[1, 0, 2, 0, 3, 0, 4, 0, 5]
p [1, 2, 3, 4, 5].intersperse { 0 }
#= >[1, 0, 2, 0, 3, 0, 4, 0, 5]
(我使用Haskell函数名:intersperse。)
答案 5 :(得分:1)
这是一个使用flat_map
和each_cons
的简单版本(可以处理多个值和/或块):
class Array
def interpolate *values
each_cons(2).flat_map do |e, _|
[e, *values, *(block_given? ? yield(e) : [])]
end << last
end
end
[1,2,3].interpolate(0, "") # => [1, 0, "", 2, 0, "", 3]
[1,2,3].interpolate(&:even?) # => [1, false, 2, true, 3]
答案 6 :(得分:1)
这就是现场:
class Array
def interpolate(t = nil)
each_with_index do |e, i|
t = yield if block_given?
insert(i, t) if i % 2 == 1
end
end
end
这是因为t
在具有当前索引的元素之前插入,这使得刚插入t
元素具有当前索引,这意味着迭代可以正常继续。
答案 7 :(得分:0)
这是一种方式:
theArray.map {|element| [element, interpolated_obj]}.flatten