2012-02-23 80 views
6

我有一個數組,並希望在所有元素之間插入一個新元素,例如join方法。例如,我有如何在Ruby數組的所有元素之間插入新元素?

[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> 

我想知道的最佳途徑。

+0

'x.push(y,{})'較短,''''和'push'都返回數組,所以你不需要'; x','inject'很慢 – 2012-02-23 22:31:45

回答

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

FYI,該功能被稱爲intersperse(至少在Haskell)。

[更新]如果你想避免(創建該數組的副本)切片:

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

我不會在Haskell中(也可能在Ruby中)做'[0 ..- 1]' – 2012-02-23 22:44:11

+0

@VictorMoroz,你會怎麼做? – 2012-02-23 22:46:39

+0

@VictorMoroz:添加了一個就地片段。 Ruby對此沒有抽象,所以我使用了tap + pop。 – tokland 2016-08-21 21:21:50

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

+1

較短版本:'' a.flat_map {| e | [e,{}]}' – 2012-02-23 22:29:29

+0

哦,真好!而且它不會壓扁空白數組。好決定。 – 2012-02-23 22:32:14

+1

只有最後一個'{}'不需要 – 2012-02-23 22:33:45

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> 
0

另外一個,它類似於Tokland的:

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

另一個相似的解決方案使用#product

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

一種方法是壓縮所需元素的另一個數組,然後用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]撬(主)> [1,2,3]。散佈( 'A')
=> [1, 「A」,2, 「一」,3]

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

inject將使用所述第一元件與啓動,所以就不需要弄亂指數。

相關問題