Ruby array filling method

Here is what I have now, and it works somewhat:

def padding(a, b, c=nil) until a[b-1] a << c end end 

This is when it works:

 a=[1,2,3] padding(a,10,"YES") =>[1, 2, 3, "YES", "YES", "YES", "YES", "YES", "YES", "YES"] a[1,2,3] padding(a,10,1) =>[1, 2, 3, 1, 1, 1, 1, 1, 1, 1] 

But it crashes when I do not enter a value for "c"

 a=[1,2,3] padding(a,10) Killed 

How do I add this to avoid a crash? In addition, how would you suggest changing this method to use it as follows:

 [1,2,3].padding(10) =>[1,2,3,nil,nil,nil,nil,nil,nil,nil] [1,2,3].padding(10, "YES") =>[1, 2, 3, "YES", "YES", "YES", "YES", "YES", "YES", "YES"] 

I saw other addition methods on SO, but they don't seem to work as intended by the authors. So, I decided to make my own shot.

+6
source share
5 answers

Do you know the Array#fill method: -

He does what you are exactly looking for. If it exists, why do you want your own.

 arup@linux-wzza :~> pry [1] pry(main)> a=[1,2,3] => [1, 2, 3] [2] pry(main)> a.fill('YES', 3...10) => [1, 2, 3, "YES", "YES", "YES", "YES", "YES", "YES", "YES"] [3] pry(main)> 

You can fill your array as you wish. This is a cool implementation. Give it a try.

Read it in the console:

 arup@linux-wzza :~> ri Array#fill = Array#fill (from ruby site) ------------------------------------------------------------------------------ ary.fill(obj) -> ary ary.fill(obj, start [, length]) -> ary ary.fill(obj, range ) -> ary ary.fill { |index| block } -> ary ary.fill(start [, length] ) { |index| block } -> ary ary.fill(range) { |index| block } -> ary ------------------------------------------------------------------------------ The first three forms set the selected elements of self (which may be the entire array) to obj. A start of nil is equivalent to zero. A length of nil is equivalent to the length of the array. The last three forms fill the array with the value of the given block, which is passed the absolute index of each element to be filled. Negative values of start count from the end of the array, where -1 is the last element. a = [ "a", "b", "c", "d" ] a.fill("x") #=> ["x", "x", "x", "x"] a.fill("z", 2, 2) #=> ["x", "x", "z", "z"] a.fill("y", 0..1) #=> ["y", "y", "z", "z"] a.fill { |i| i*i } #=> [0, 1, 4, 9] a.fill(-2) { |i| i*i*i } #=> [0, 1, 8, 27] 
+11
source

He is killed because you are entering an endless cycle. until a[b-1] will not end, because when you add nils to the array, you will get:

 a == [1, 2, 3, nil, nil, nil, nil, nil, nil, nil] 

after several iterations, and [b-1] will be nil , which is false. Until it stops.

About the second question, it is easy to extend the existing Array class:

 class Array def padding(i, value=nil) (i - length).times { self << value } self end end 

The result, as you expected:

 [1,2,3].padding(10) #=> [1, 2, 3, nil, nil, nil, nil, nil, nil, nil] [1,2,3].padding(10, "YES") #=> [1, 2, 3, "YES", "YES", "YES", "YES", "YES", "YES", "YES"] 

Note that the method modifies the existing array (therefore, due to Ruby conventions, you should call padding! ):

 a = [1,2,3] #=> [1, 2, 3] a.padding(10, "YES") #=> [1, 2, 3, "YES", "YES", "YES", "YES", "YES", "YES", "YES"] a #=> [1, 2, 3, "YES", "YES", "YES", "YES", "YES", "YES", "YES"] 

But of course, you can easily create a version of a method that does not change. I suggested that you want to modify the array because your original method did this.

+3
source

Arup nailed it, but here is another way:

 def padding(a,b,c) [*a, *[c]*b] end a=[1,2,3] padding(a,5,"YES") #=> [1, 2, 3, "YES", "YES", "YES", "YES", "YES"] 
+3
source

The problem is that nil evaluates to false, so until a[b-1] never true when [b-1] contains nil ... so you loop forever until you run out of memory.

better to do ...

 def padding(a, b, c=nil) until a.size >= b a << c end end 

EDIT (yes, Arup's answer is pretty neat)

You can do it as a single line, which is a little more compact ...

 def padding(a, b, c=nil) a << c until a.size >= b end 
+2
source

To specifically implement your padding method in an array:

 module Padding refine Array do def padding(new_length, element=nil) if self.size < new_length self.concat(Array.new(new_length - self.size, element)) end end end end using Padding puts [1,2,3].padding(10).inspect # => [1, 2, 3, nil, nil, nil, nil, nil, nil, nil] puts [1,2,3].padding(10, "YES").inspect # => [1, 2, 3, "YES", "YES", "YES", "YES", "YES", "YES", "YES"] 

EDIT: Forgot about Array#fill . Arup's answer is cool (even if you need to say fill(3, 7) instead of fill(-1, 10) , since the latter gives the wrong result). It would be better to use it instead of concat(Array.new(...)) . Good.:)

0
source

Source: https://habr.com/ru/post/973381/


All Articles