可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
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.
回答1:
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.
回答2:
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:
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"]
回答4:
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
回答5:
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. :)