13

Here's what I have now and it is somewhat working:

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 should I append this to avoid a crash? Additionally, 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've seen other padding methods on SO, but they don't seem to be working as intended by the authors. So, I decided to give making my own a shot.

6 Answers 6

18

Do you know Array#fill method :-

It does, what you exactly looking for. If it exist, why 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, whatever way you want. It is a cool implementation. Give it a try.

Read it in your 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]
Sign up to request clarification or add additional context in comments.

5 Comments

Nice approach. If you represent what OP asked with [1,2,3].padding(10, "YES") with #fill => [1, 2, 3].fill('YES', 3...10) where 3 can be replaced by Array#length
@Nishu No objections! :-)
This is very comprehensive. Thank you very much for your answer!
This is the way. It's a little confusing at first on how to use it to pad the Array but once you get it, it's gold. And it's built in. Heck, even creating a pad method but base it off of this would be better than creating your own from scratch. Nice work Arup!
To do what the OP asked for the 3 needs to be replaced by Array#length and the 10 by 10 - Array#length. See my answer.
6

It is killed, because you are entering infinite loop. until a[b-1] will not finish, because when you add nils to the array, you will get:

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

after few iterations and a[b-1] will be nil, which is falsey. Until will never stop.

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

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

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 the method about modifies existing array (so due to Ruby conventions should be called 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 easy create the version of the method which doesn't modify. I assumed you want to modify the array, because your original method did it.

1 Comment

Thank you for pointing that out! I completely forgot about the innate falseness of nil.
3

Arup has nailed it, but here's 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"]

Comments

2

The problem is that nil is evaluated as false, so until a[b-1] is never true when a[b-1] contains nil... so you loop forever until you're 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 this as a one-liner, which is a bit more compact...

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

Comments

0

To specifically implement your padding method on 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), as the latter gives the wrong result). It would have been better to use it instead of concat(Array.new(...)). Eh well. :)

Comments

0

The answer which uses Array#fill does not do exactly what the OP requested if the array can be of variable length. This does:

module ArrayExtensions
  def pad(pad_to_length, object = nil)
    fill(object, size, pad_to_length - size)
  end

  Array.prepend ArrayExtensions
end

[1, 2, 3].pad(10)
#=> [1, 2, 3, nil, nil, nil, nil, nil, nil, nil]

[1, 2, 3, 4].pad(10)
#=> [1, 2, 3, 4, nil, nil, nil, nil, nil, nil]

arr = Array.new(11, '')
#=> ["", "", "", "", "", "", "", "", "", "", ""]

arr.pad(10)
#=> ["", "", "", "", "", "", "", "", "", "", ""] # unchanged

Array.new(11, '').pad(14, :foo)
#=> ["", "", "", "", "", "", "", "", "", "", "", :foo, :foo, :foo]

Pretty amazed Array doesn't have this method already, I'll suggest it.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.