How to insert a new element in between all elements of a Ruby array?

匿名 (未验证) 提交于 2019-12-03 03:08:02

问题:

I have an Array and want to insert a new element in between all elements, someway like the join method. For example, I have

[1, [], "333"] 

and what I need is

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

Note a new empty hash was inserted in between all elements.

Edit: Currently what I have is:

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> 

I want to know the best way.

回答1:

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

FYI, that function is called intersperse (at least in Haskell).

[Update] If you want to avoid the slice (that created a copy of the array):

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


回答2:

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


回答3:

You could do something like:

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

You need to do .flatten(1) because it will flatten your blank array without it.

Or as @David Grayson says in the comment, you can do a flat_map which will do the same thing.

a.flat_map {|e| [e, {}]} => [1, {}, [], {}, "333", {}] 

@tokland has the correct answer if the last {} is not necessary. You return a slice from 0 to length - 1 or [0..-1].



回答4:

Another similar solution uses #product :

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


回答5:

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:

Another one that's similar to Tokland's:

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


回答7:

One approach is to zip another array of desired elements and then flatten it with depth = 1:

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

You can extend Array to make this behavior more accessible.

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

e.g.,

[43] pry(main)> [1,2,3].intersperse('a')
=> [1, "a", 2, "a", 3]



回答8:

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

inject will use the first element to start with, so you don't need to mess with indices.



标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!