如何插入数组?

时间:2011-12-22 15:41:57

标签: ruby arrays ruby-1.9

我想使用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虽然看起来很漂亮,但速度很慢。

8 个答案:

答案 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_mapeach_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