Способ заполнения массива в 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(...)). Ну ладно. :)