如何在Ruby数组的所有元素之间插入一个新元素?

时间:2012-02-23 22:17:59

标签: ruby arrays

我有一个数组,想在所有元素之间插入一个新元素,就像join方法一样。例如,我有

[1, [], "333"]

我需要的是

[1, {}, [], {}, "333"]

注意在所有元素之间插入了一个新的空哈希。

编辑: 目前我所拥有的是:

irb(main):028:0> a = [1, [], "333"]
=> [1, [], "333"]
irb(main):029:0> a = a.inject([]){|x, y| x << y; x << {}; x}
=> [1, {}, [], {}, "333", {}]
irb(main):030:0> a.pop
=> {}
irb(main):031:0> a
=> [1, {}, [], {}, "333"]
irb(main):032:0>

我想知道最好的方法。

8 个答案:

答案 0 :(得分:14)

[1, 2, 3].flat_map { |x| [x, :a] }[0...-1]
#=> [1, :a, 2, :a, 3]

仅供参考,该功能称为intersperse(至少在Haskell中)。

[更新]如果要避免切片(创建数组的副本):

[1, 2, 3].flat_map { |x| [x, :a] }.tap(&:pop)
#=> [1, :a, 2, :a, 3]

答案 1 :(得分:2)

另一个类似的解决方案使用#product

[1, 2, 3].product([{}]).flatten(1)[0...-1]
# => [ 1, {}, 2, {}, 3 ]

答案 2 :(得分:1)

a = [1,2,3]
h, *t = a
r = [h]
t.each do |e|
  r.push({}, e)
end
r #=> [1, {}, 2, {}, 3]

答案 3 :(得分:1)

您可以执行以下操作:

a = [1, [], "333"]
new_a = a.collect {|e| [e, {}]}.flatten(1)
=> [1, {}, [], {}, "333", {}]

您需要执行.flatten(1)因为它会在没有它的情况下展平您的空白数组。

或者正如@David Grayson在评论中所说的那样,你可以做flat_map同样的事情。

a.flat_map {|e| [e, {}]}
=> [1, {}, [], {}, "333", {}]
如果不需要最后一个{},

@tokland有正确的答案。您将切片从0返回到长度 - 1或[0..-1]

答案 4 :(得分:1)

一种方法是压缩另一个所需元素数组,然后用depth = 1压缩它:

> arr = [1, [], "333"]
> element = {}
> interspersed = arr.zip([element] * (arr.size - 1)).flatten(1).compact
> # [1, {}, [], {}, "333" ]

您可以扩展Array以使此行为更易于访问。

class Array
  def intersperse(elem)
    self.zip([elem] * (self.size - 1)).flatten(1).compact
  end
end

例如,

  

[43] pry(主要)&gt; [1,2,3] .intersperse(&#39;一个&#39;)
  =&GT; [1,&#34; a&#34;,2,&#34; a&#34;,3]

答案 5 :(得分:0)

irb(main):054:0* [1, 2, 3, 4, 5, 6, 7, 8, 9].each_slice(1).flat_map {|e| e << "XXX"}[0...-1]
=> [1, "XXX", 2, "XXX", 3, "XXX", 4, "XXX", 5, "XXX", 6, "XXX", 7, "XXX", 8, "XXX", 9]
irb(main):055:0> [1, 2, 3, 4, 5, 6, 7, 8, 9].each_slice(2).flat_map {|e| e << "XXX"}[0...-1]
=> [1, 2, "XXX", 3, 4, "XXX", 5, 6, "XXX", 7, 8, "XXX", 9]
irb(main):056:0> [1, 2, 3, 4, 5, 6, 7, 8, 9].each_slice(3).flat_map {|e| e << "XXX"}[0...-1]
=> [1, 2, 3, "XXX", 4, 5, 6, "XXX", 7, 8, 9]
irb(main):057:0> [1, 2, 3, 4, 5, 6, 7, 8, 9].each_slice(4).flat_map {|e| e << "XXX"}[0...-1]
=> [1, 2, 3, 4, "XXX", 5, 6, 7, 8, "XXX", 9]
irb(main):058:0> [1, 2, 3, 4, 5, 6, 7, 8, 9].each_slice(5).flat_map {|e| e << "XXX"}[0...-1]
=> [1, 2, 3, 4, 5, "XXX", 6, 7, 8, 9]
irb(main):059:0> [1, 2, 3, 4, 5, 6, 7, 8, 9].each_slice(6).flat_map {|e| e << "XXX"}[0...-1]
=> [1, 2, 3, 4, 5, 6, "XXX", 7, 8, 9]
irb(main):060:0> [1, 2, 3, 4, 5, 6, 7, 8, 9].each_slice(7).flat_map {|e| e << "XXX"}[0...-1]
=> [1, 2, 3, 4, 5, 6, 7, "XXX", 8, 9]
irb(main):061:0> [1, 2, 3, 4, 5, 6, 7, 8, 9].each_slice(8).flat_map {|e| e << "XXX"}[0...-1]
=> [1, 2, 3, 4, 5, 6, 7, 8, "XXX", 9]
irb(main):062:0> [1, 2, 3, 4, 5, 6, 7, 8, 9].each_slice(9).flat_map {|e| e << "XXX"}[0...-1]
=> [1, 2, 3, 4, 5, 6, 7, 8, 9]
irb(main):063:0>

答案 6 :(得分:0)

另一个与Tokland相似的人:

xs.inject([]){|x,y| x << y << {}}[0...-1]

答案 7 :(得分:0)

[1, 2, 3, 4, 5].inject { |memo, el| Array(memo) << {} << el }
#=> [1, {}, 2, {}, 3, {}, 4, {}, 5]

inject将使用第一个元素开头,因此您不需要乱用索引。