Способ заполнения массива в Ruby
вот что у меня сейчас и это несколько работает:
def padding(a, b, c=nil)
until a[b-1]
a << c
end
end
это когда он работает:
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]
но он падает, когда я не ввожу значение для"c"
a=[1,2,3]
padding(a,10)
Killed
как я должен добавить это, чтобы избежать аварии? Кроме того, как бы вы предложили изменить этот метод, чтобы использовать его следующим образом:
[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"]
Я видел другие методы заполнения на SO, но они, похоже, не работают так, как предполагали авторы. Итак, я решил сделать мой собственный выстрел.
5 ответов
его убили, потому что вы входите в бесконечный цикл. until a[b-1]
не закончит, потому что, когда вы добавите nils в массив, вы получите:
a == [1, 2, 3, nil, nil, nil, nil, nil, nil, nil]
после нескольких итераций и A[b-1] будет nil
, который является falsey. Пока не прекратится.
о втором вопросе, легко расширить существующий класс массива:
class Array
def padding(i, value=nil)
(i - length).times { self << value }
self
end
end
результат, как вы ожидали:
[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"]
обратите внимание на способ о изменение существующий массив (из-за к условностям Ruby следует называть 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"]
но, конечно, вы можете легко создать версию метода, который не изменяется. Я предположил, что вы хотите изменить массив, потому что это сделал ваш исходный метод.
вы знаете Array#fill
способ :-
это делает то, что вы именно ищете. Если она существует, почему вы хотите свою собственную?
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)>
вы можете заполнить Ваш массив, как вы хотите. Это классная реализация. Попробуй.
читать это в консоли :
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]
Arup прибил его, но вот другой способ:
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"]
проблема в том, что nil оценивается как false, поэтому until a[b-1]
никогда не верно, когда A[b-1] содержит ноль... так что ты будешь петлять вечно, пока не потеряешь память.
лучше сделать...
def padding(a, b, c=nil)
until a.size >= b
a << c
end
end
изменить (Да, Ответ Арупа довольно аккуратный)
вы можете сделать это как ОДН-вкладыш, который немного более компактен...
def padding(a, b, c=nil)
a << c until a.size >= b
end
специально реализовать ваш padding
метод на массиве:
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: забыл о Array#fill
. Ответ Arup классный (даже если вам нужно сказать fill(3, 7)
вместо fill(-1, 10)
, так как последний дает неправильный результат). Было бы лучше использовать его вместо concat(Array.new(...))
. Ну ладно. :)