切片
返回列表中给定第一个和最后一个位置之间的子序列。
如果你想要列表的一部分,你可以取列表的切片。根据你想要的切片,不同的语言提供了不同的运算符。
最通用的形式允许你切出任何范围的元素。
[1,2,3,4,5,6].slice(2..4) # => [3, 4, 5]
(subvec [1 2 3 4 5 6] 2 5) ;; => [3 4 5]
这两个基本示例提出了一些要点。首先,大多数语言使用从零开始的索引,因为程序员自然地通过说“0,1,2… 9”来数到十。
Ruby 使用包含范围指定切片,而 clojure 使用两个数字,开始包含,结束排除。Ruby 的范围表示法允许使用以下方法排除结束
ruby…[1,2,3,4,5,6].slice(2...5) # => [3, 4, 5]
我很少使用三点形式,一些程序员不喜欢使用它,因为“...”和“..”之间的区别非常微妙。
Ruby 可以使用数组参数进行切片。
ruby…[1,2,3,4,5,6][2..4] # => [3, 4, 5]
这种形式在管道形式中可能读起来不太好。
Clojure 的 subvec 函数只适用于向量,而不适用于一般的列表。它在向量上很快(因为它们是索引的),但在 clojure 列表的其他形式上不会很快,因此它对操作向量的限制有助于避免性能意外,而牺牲了操作使用的一般性。Subvec 也不符合 clojure 管道的约定,因为集合参数不是最后一个参数,所以它不适用于 ->>
。
在 clojure 中,你可以省略第二个参数,从第一个切片到列表的末尾,在 ruby 中,你可以使用范围上的负数来做到这一点。
[1,2,3,4,5,6].slice(2..-1) # => [3, 4, 5, 6]
(subvec [1 2 3 4 5 6] 2) ;; => [3 4 5 6]
Ruby 的范围可以有负参数,从列表的末尾开始计数。
ruby…[1,2,3,4,5,6].slice(-4..-2) # => [3, 4, 5]
许多语言更喜欢使用单独的 take 和 drop 函数,而不是使用通用的切片操作。Take 返回第一个元素(相当于 ruby 中的 slice(0..2)
)。
[1,2,3,4,5,6].take(3) # => [1, 2, 3]
(take 3 [1 2 3 4 5 6]) ;; => (1 2 3)
Drop 丢弃第一个元素(ruby 中的 slice(-3..-1)
)。
[1,2,3,4,5,6].drop(3) # => [4, 5, 6]
(drop 3 [1 2 3 4 5 6]) ;; => (4 5 6)
你可以通过管道连接 take 和 drop 来形成切片。
[1,2,3,4,5,6].take(5).drop(2) # => [3, 4, 5]
(drop 2 (take 5 [1 2 3 4 5 6])) ;; => (3 4 5)
请注意,这些数字对应于 ruby 切片运算符中的排他范围。
take-drop 方法适用于惰性列表,因为这两个操作都可以在不解析整个列表的情况下完成。
如果你需要从列表的末尾开始工作,clojure 提供了 take-last
和 drop-last
。
(take-last 2 [1 2 3 4 5 6]) ;; => (5 6) (drop-last 2 [1 2 3 4 5 6]) ;; => (1 2 3 4)