Method for padding an array in Ruby

2020-02-13 08:26发布

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.

5条回答
狗以群分
2楼-- · 2020-02-13 08:45

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]
查看更多
爷的心禁止访问
3楼-- · 2020-02-13 08:50

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"]
查看更多
Luminary・发光体
4楼-- · 2020-02-13 08:58

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. :)

查看更多
家丑人穷心不美
5楼-- · 2020-02-13 09:03

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
查看更多
贪生不怕死
6楼-- · 2020-02-13 09:05

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.

查看更多
登录 后发表回答