在Ruby 1.8.7中,与Array#rotate相当的方法是什么?

6
a = [ "a", "b", "c", "d" ]
a.rotate         #=> ["b", "c", "d", "a"]

#rotate是Ruby 1.9中Array的方法。我想在Ruby 1.8.7中实现这个功能。请问最理想的代码是什么?

4个回答

11
如果您需要在旧版的Ruby中使用Array#rotaterotate!方法,可以通过require 'backports/1.9.2/array/rotate'来实现。
这样做有两个好处,一是避免重新发明轮子,二是确保实现符合RubySpec标准,可以处理所有边界情况,并且与Ruby 1.9兼容。
例如,在给出的两个答案中,都不能处理[]的情况!

Backports是一个宝石(gem),因此您需要按照安装说明进行“gem install backports”安装。 - Marc-André Lafortune
谢谢,我成功安装并使用了这个 gem;Cygwin 使得安装那些不在默认软件包中的东西变得令人沮丧。 - Hunter McMillen

9
您可以使用 a.push(a.shift) 来实现相同的效果。它基本上移除了第一个元素(shift),并将其附加到末尾(push)。

但它也改变了原始数组...有没有一种方法可以在不改变原始数组的情况下进行操作? - rubyprince
这是针对rotate!的,它会修改数组,但不适用于空数组[]。它也不太兼容1.9版本,因为它不接受旋转元素数量的参数。请参见我的答案。 - Marc-André Lafortune

2

很抱歉来晚了... ;)

类似于a.rotate!(n)

a += a.shift(n)

它适用于a = []。但是,与a.rotate!(n)不同的是,如果n大于a的长度,则不会执行任何操作。

以下代码可以保留a的值,并允许n大于a.length工作,但代价是有点复杂:

a.last(a.length - (n % a.length)) + a.first(n % a.length)

这显然最好是将 n % a.length 单独计算一次,然后将整个方法封装到 Array 中作为补丁方法。
class Array
  def rot(n)
    m = n % self.length
    self.last(self.length - m) + self.first(m)
  end
end

你的“rotate”版本确实改变了原始数组“a”。 - rubyprince
@rubyprince 是的,确实如此。我认为Ruby在其方法定义上有点不一致。我认为shift应该保持数组不变,而他们应该有一个shift!来直接修改它。 - lurker
shift 方法实际上返回被移除的元素,并且它会改变原始数组。非常有用。 - rubyprince
@rubyprince 是的,我知道。这就是使它在短的“rotate”表达式中工作的原因,但会有修改原始数组的副作用。 - lurker

1

对于没有参数的rotate!版本,gnab的很好。如果你想要一个非破坏性的版本,带有可选参数:

class Array
  def rotate n = 1; self[n..-1]+self[0...n] end
end

如果 n 可能会变得比数组的长度还要大:
class Array
  def rotate n = 1; return self if empty?; n %= length; self[n..-1]+self[0...n] end
end

两者都无法处理[]。请参考我的回答。 - Marc-André Lafortune
在Marc-Andre的指点下,我修复了第二个例子,但我同意使用backports会更好。我没有修复第一个例子,因为它可能没有用处。 - sawa

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