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

我有一个数组,想要在所有元素之间插入一个新元素,就像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 < [1, {}, [], {}, "333", {}] irb(main):030:0> a.pop => {} irb(main):031:0> a => [1, {}, [], {}, "333"] irb(main):032:0> 

我想知道最好的方法。

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

仅供参考,该function称为散布 (至少在Haskell中)。

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

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

你可以这样做:

 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]

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

 [1, 2, 3].product([{}]).flatten(1)[0...-1] # => [ 1, {}, 2, {}, 3 ] 
 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> 

另一个与Tokland相似的:

 xs.inject([]){|x,y| x << y << {}}[0...-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(main)> [1,2,3] .intersperse(’a’)
=> [1,“a”,2,“a”,3]

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

inject将使用第一个元素开始,所以你不需要乱用索引。