Ruby数组中除最后一个元素外的所有元素


139

假设我有一个Ruby数组

a = [1, 2, 3, 4]

如果我只需要第一项,我可以写a.drop(1),这很棒。但是,如果我要除最后一项以外的所有东西,我只能这样想

a[0..-2]   # or
a[0...-1]

但是这些看上去都不如使用干净drop。还有其他内置的方式吗?


根据globalnerdy.com/2008/07/10/…,下降为Ruby 1.9,而不是1.8.6
Andrew Grimm

那么性能如何呢?如果我将这些答案重复使用1000次,那么哪个会获胜呢?
Ninad

换句话说,哪个解决方案不遍历数组?
Ninad

另一种方式--([a.size])
约翰

Answers:


128

也许...

a = t               # => [1, 2, 3, 4]
a.first a.size - 1  # => [1, 2, 3]

要么

a.take 3

要么

a.first 3

要么

a.pop

这将返回最后一个,并在数组之前保留所有内容

让计算机在晚餐时正常工作:

a.reverse.drop(1).reverse

要么

class Array
  def clip n=1
    take size - n
  end
end
a          # => [1, 2, 3, 4]
a.clip     # => [1, 2, 3]
a = a + a  # => [1, 2, 3, 4, 1, 2, 3, 4]
a.clip 2   # => [1, 2, 3, 4, 1, 2]

5
Array对我来说,添加方法似乎是最好的方法。大多数项目最终都带有一个core_ext.rb很少扩展名的文件。某些库实际上是所有这样的扩展:ActiveSupport例如。
rfunduk

很有意思,我想知道它有多普遍。人们如何看待诗歌模式?
DigitalRoss

5
有人如何将这种clip方法提交给Ruby社区?我真的认为这应该在那里,并且猴子修补是错误的事情
Droogans

7
我喜欢这个a.reverse.drop(1).reverse策略。;-)
Alex

92

出于好奇,您为什么不喜欢a[0...-1]?您想获取数组的一个切片,所以切片运算符似乎是惯用的选择。

但是,如果您需要在各处调用此方法,则始终可以选择向Array类添加名称更友好的方法,如DigitalRoss建议的那样。也许像这样:

class Array
    def drop_last
        self[0...-1]
    end
end

当滴很干净时,看起来好像很杂乱。这没什么大不了的,但是很难一眼就确认它是正确的。drop_last顺便说一句,我更喜欢您的名字……
彼得

我喜欢使用-1这么多比使用。长度优雅
威尔弥敦道

很好奇,那第三个是什么意思.
约书亚·品特

5
...表示不包括最后一项,-1是最后一项。如果您做了两个点,那么它将包括最后一个项目,三个点则将不包括最后一个项目。
ckim 2015年

注意使用slice运算符获取数组的尾部:它可能返回nil[][1..-1]-> nil[][0...-1]->[]
Michael

57

另一个很酷的把戏

>> *a, b = [1,2,3]
=> [1, 2, 3]
>> a
=> [1, 2]
>> b
=> 3

很好,不知道Ruby有这个吗?因此a, *b = [1,2,3],让我们以经典的car / cdr方式查看阵列。
Nobbynob Littlun

老实说,我什至不记得写那条评论了:D现在删除了它……
Petr Bela

太简单了,很好。THX
microspino

43

如果要对pop()数组执行操作(这将导致删除最后一项),但是您有兴趣获取数组而不是弹出元素,则可以使用tap(&:pop)

> arr = [1, 2, 3, 4, 5]
> arr.pop
=> 5
> arr
=> [1, 2, 3, 4]
> arr.tap(&:pop)
=> [1, 2, 3]

这个答案在语义上对该用户最有意义。镜像操作就在眼前,它使用易于解释和简洁的单词。
Jerome

2
那是一些精巧的Ruby。
emptywalls


23

例如,如何增强drop方法本身?

class Array
  def drop(n)
    n < 0 ? self[0...n] : super
  end
end

然后,您可以使用负数大小从结尾删除元素,如下所示:

[1, 2, 3, 4].drop(-1) #=> [1, 2, 3]
[1, 2, 3, 4].drop(-2) #=> [1, 2]

19

a[0...-1]似乎是最好的方法。正是为此目的而创建了数组切片语法。

另外,如果您不介意修改数组,则可以调用a.pop

>> a = [1, 2, 3, 4]
>> a.pop
>> a
=> [1, 2, 3]

您还可以将最后一个元素分配给变量以供以后使用:b = a.pop
Viktor Fonic 2013年

12

摆脱一行中的最后一个元素,其余返回

[1, 2, 4, 5, 6].reverse.drop(1).reverse

认真地

[1,2,3,4][0..-2]
#=> [1,2,3]

11

这是这样的:

[1,2,3,4,5][0..-1-1]

但是,让我们解释一下它是如何工作的:

a = [1,2,3,4,5]

下一个示例将返回从0位置到最后一个位置的所有记录

a[0..-1]
=> [1, 2, 3, 4, 5]

下一个示例将从1个位置返回记录到最后一个

a[1..-1]
=> [2, 3, 4, 5]

在这里,您拥有所需的东西。下一个示例将记录从0位置返回到last-1

a[0..-1-1]
=> [1, 2, 3, 4]

1
您可以写-2而不是-1-1
bfontaine 2015年

您可以这样做a[0...-1](注意第三个点),并得到与相同的结果a[0..-1-1],因为第三个点告诉它排除了结束元素。请参阅了解更多详情。
朱利安


2

答案: a.τwτ,但是您必须先安装Pyper ...

Pyper简介:您知道Lispy carcdr返回数组的“第一”和“其余”吗?为了满足您的需求,我扩展了此Lispy机制。它叫做pyper,它还允许您访问2nd,2nd,3rd,3d和last,除了last等以外的所有内容。虽然写起来并不多,但是它也允许字母组合,就像caarcadrcdadar等从Lisp的已知:

# First, gem install pyper
require 'pyper'
include Pyper
a = %w/lorem ipsum dolor sit amet/
# To avoid confusion with other methods, and also because it resembles a rain gutter,
# Greek letter τ is used to delimit Pyper methods:
aaτ #=> "lorem"
adτ #=> ["ipsum", "dolor", "sit", "amet"]
abτ #=> "ipsum"
aeτ #=> ["dolor", "sit", "amet"]
acτ #=> "dolor" (3rd)
azτ #=> "amet" (last)
ayτ #=> "sit" (2nd from the end)
axτ #=> "dolor" (3rd from the end)

最后,您的问题的答案:

awτ #=> ["lorem", "ipsum", "dolor", "sit"] (all except last)

还有更多:

auτ #=> ["lorem", "ipsum", "dolor"] (all except last 2)
a1τ #=> ["lorem", "ipsum"] (first 2)
a8τ #=> (last 2)
a7τ #=> (last 3)

成分:

awydτ #=> "olor" (all except 1st letter of the last word of all-except-last array)

还有很多命令字符,而不仅仅是a..fu..z并且0..9,最值得注意的是m,意思是map:

awmbτ #=> ["o", "p", "o", "i"] (second letters of all-except-last array)

但是其他命令字符太热了,目前还不太容易使用。


1
我在4月1日阅读此书,所以我以为这是个玩笑...不。不知道Ruby有没有这些东西。:)
约书亚·品特

1

这将创建一个包含原始元素的最后一个元素的新数组:

ary2 = ary.dup
ary2.pop

请注意,其他一些建议使用#pop。如果可以修改数组就可以了。如果您对此不满意,请首先将数组复制,如本例所示。


1
如果可以在适当位置修改数组,则其他一些建议使用#pop。如果您对此不满意,请首先将数组复制,如本例所示。
alegscogs 2011年

这是一个重要的评论。您也可以将其添加到您的答案中。由于#pop没有爆炸(!),因此它修改了原始数组的事实可能使人们逃脱。
mjnissim 2013年

如果数组很大,这种方法效率很低。
juliangonzalez 18/12/23

1

我经常发现自己想要数组的最后n个元素。我已经建立了自己的功能,以比其他解决方案更具可读性的方式执行此操作:

class Array
  def all_but_the_last(n)
    self.first(self.size - n)
  end
end

现在,您可以执行以下操作:

arr = ["One", "Two", "Three", "Four", "Five"]
# => ["One", "Two", "Three", "Four", "Five"]

arr.all_but_the_last(1)
# => ["One", "Two", "Three", "Four"]

arr.all_but_the_last(3)
# => ["One", "Two"]

arr.all_but_the_last(5)
# => []

arr.all_but_the_last(6)
# ArgumentError: negative array size

我故意允许ArgumentError,以便调用方负责他们如何使用此方法。我很想听听对这种方法的评论/批评。


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.