如何在Ruby中返回数组的一部分?

160

使用以下代码,我可以在 Python 中返回列表的一部分:

foo = [1,2,3,4,5,6]
bar = [10,20,30,40,50,60]
half = len(foo) / 2
foobar = foo[:half] + bar[half:]

由于 Ruby 中所有内容都在数组中完成,我想知道是否有类似的东西。

6个回答

244

是的,Ruby与Python具有非常相似的数组切片语法。以下是数组索引方法的 ri 文档:

--------------------------------------------------------------- Array#[]
     array[index]                -> obj      or nil
     array[start, length]        -> an_array or nil
     array[range]                -> an_array or nil
     array.slice(index)          -> obj      or nil
     array.slice(start, length)  -> an_array or nil
     array.slice(range)          -> an_array or nil
------------------------------------------------------------------------
     Element Reference---Returns the element at index, or returns a 
     subarray starting at start and continuing for length elements, or 
     returns a subarray specified by range. Negative indices count 
     backward from the end of the array (-1 is the last element). 
     Returns nil if the index (or starting index) are out of range.

        a = [ "a", "b", "c", "d", "e" ]
        a[2] +  a[0] + a[1]    #=> "cab"
        a[6]                   #=> nil
        a[1, 2]                #=> [ "b", "c" ]
        a[1..3]                #=> [ "b", "c", "d" ]
        a[4..7]                #=> [ "e" ]
        a[6..10]               #=> nil
        a[-3, 3]               #=> [ "c", "d", "e" ]
        # special cases
        a[5]                   #=> nil
        a[6, 1]                #=> nil
        a[5, 1]                #=> []
        a[5..10]               #=> []

6
为什么a[5, 1]和a[6, 1]不同? - dertoni
4
为什么Array.slice()在设置length=n时的行为会与预期不同? - michelpm
34
为了获取从第三个元素到最后一个元素,可以使用 a[2..-1]。 为了获取从第三个元素到倒数第二个元素,可以使用 a[2...-1] - Clever Programmer
1
@Rafeh 干杯,一直在想这个垃圾怎么用,-1起了作用。 - pronebird
2
@CleverProgrammer 的语法比被接受的答案更接近 Python。我喜欢 Ruby,但必须说 Python 的语法更短、更清晰。作为额外的奖励,可以指定步骤:range(10)[:5:-1] - Eric Duminil

30

如果您想在索引i处分割/切割数组,

arr = arr.drop(i)

> arr = [1,2,3,4,5]
 => [1, 2, 3, 4, 5] 
> arr.drop(2)
 => [3, 4, 5] 

21

Ruby 2.6 开始/结束范围

(..1)
# or
(...1)

(1..)
# or
(1...)
[1,2,3,4,5,6][..3]
=> [1, 2, 3, 4]

[1,2,3,4,5,6][...3]
 => [1, 2, 3]

ROLES = %w[superadmin manager admin contact user]
ROLES[ROLES.index('admin')..]
=> ["admin", "contact", "user"]

1
最好能稍微解释一下,特别是因为 [..3] 返回了一个不直观的结果。 - not2qubit

18
你可以使用 slice() 来实现此操作:
>> foo = [1,2,3,4,5,6]
=> [1, 2, 3, 4, 5, 6]
>> bar = [10,20,30,40,50,60]
=> [10, 20, 30, 40, 50, 60]
>> half = foo.length / 2
=> 3
>> foobar = foo.slice(0, half) + bar.slice(half, foo.length)
=> [1, 2, 3, 40, 50, 60]

顺便说一下,据我所知,Python中的“列表”实际上只是高效实现的动态增长数组。开头插入的时间复杂度为O(n),末尾插入的平均时间复杂度为O(1),随机访问的时间复杂度为O(1)。


你的意思是在第二个切片中使用bar数组吗? - Samuel
FYI:slice!()不会直接修改数组,而是“通过索引(可选地最多长度元素)或范围删除给定的元素”。参见http://ruby-doc.org/core-2.2.3/Array.html#method-i-slice-21。 - Joshua Pinter
@joshuapinter 谢谢自己!我刚刚又被这个问题咬了一次(显然)。 - Joshua Pinter

9
另一种方法是使用range方法。
foo = [1,2,3,4,5,6]
bar = [10,20,30,40,50,60]
a = foo[0...3]
b = bar[3...6]

print a + b 
=> [1, 2, 3, 40, 50 , 60]

3

我认为范围(ranges)非常适合这个场景:

def first_half(list)
  list[0...(list.length / 2)]
end

def last_half(list)
  list[(list.length / 2)..list.length]
end

然而,非常小心地考虑您的范围是否包括端点。在长度为奇数的列表中,这变得至关重要,因为您需要选择在哪里断开中间部分。否则,您将会重复计算中间元素。

上述示例将始终将中间元素放在后一半。


你可以使用 (list.length / 2.0).ceil 来确保将中间元素始终放在前半部分,如果需要的话。 - Sorashi

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