在Ruby中填充数组的方法

12

以下是目前我拥有的内容,它在某种程度上正在发挥作用:

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个回答

16

你知道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]

1
不错的方法。如果你用 [1,2,3].padding(10, "YES") 来表示 OP 所要求的,可以使用 #fill => [1, 2, 3].fill('YES', 3...10),其中 3 可以被替换为 Array#length - nishu
@Nishu 没有异议! :-) - Arup Rakshit
这非常全面。非常感谢您的回答! - marinatedpork

6

你的程序已经被终止,因为你进入了无限循环。当你向数组添加nil值时,until a[b-1]不会结束,因为它会一直等待数组填满。

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

经过几次迭代,a [ b-1 ] 将变为 nil,这是假值。 直到循环将永远不会停止。

关于第二个问题,扩展现有的 Array 类很容易:

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"]

请注意以下有关 padding! 的方法,它会 修改 现有数组(根据 Ruby 惯例应该这样称呼)。
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"]

当然,你可以轻松创建不修改数据的方法。我认为你想要修改数组,因为你原来的方法是这样做的。

谢谢你指出这一点!我完全忘记了 nil 的固有虚假性。 - marinatedpork

3

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"]

2
问题在于nil被视为false,因此当a[b-1]包含nil时,until a[b-1]永远不会为true...所以你会无限循环直到内存用尽。
更好的做法是...
def padding(a, b, c=nil)
  until a.size >= b
    a << c
  end
end

编辑(是的,Arup的答案非常简洁)

你可以在一行代码中实现这个功能,更加紧凑...

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

0
为了专门在数组上实现你的“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"]

编辑:忘了Array#fill。Arup的回答很棒(即使你需要说fill(3, 7)而不是fill(-1, 10),因为后者会得到错误的结果)。最好使用它代替concat(Array.new(...))。唉,哈哈。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接