在Python中,有一种方便的方法可以获取名为“切片”的列表的一部分:
a = [1,2,3,4,5,6,7,8,9,10] # ≡ a = range(1,10)
a[:3] # get first 3 elements
a[3:] # get all elements except the first 3
a[:-3] # get all elements except the last 3
a[-3:] # get last 3 elements
a[3:7] # get 4 elements starting from 3rd (≡ from 3rd to 7th exclusive)
a[3:-3] # get all elements except the first 3 and the last 3
在Clojure中使用clojure.repl/doc
,我找到了所有这些的等价物,但我不确定它们是不是惯用的。
(def a (take 10 (iterate inc 1)))
(take 3 a)
(drop 3 a)
(take (- (count a) 3) a)
(drop (- (count a) 3) a)
(drop 3 (take 7 a))
(drop 3 (take (- (count a) 3) a))
我的问题是:如何在Clojure中切片序列?换句话说,返回序列不同部分的正确方法是什么?
答案 0 :(得分:31)
您可以使用count
或take-last
来简化使用drop-last
的所有内容:
(def a (take 10 (iterate inc 1)))
(take 3 a) ; get first 3 elements
(drop 3 a) ; get all elements except the first 3
(drop-last 3 a) ; get all elements except the last 3
(take-last 3 a) ; get last 3 elements
(drop 3 (take 7 a)) ; get 4 elements starting from 3
(drop 3 (drop-last 3 a)) ; get all elements except the first and the last 3
正如下面的评论中所建议的那样,您可以使用->>
宏将几个操作“线程化”在一起。例如,最后两行也可以这样写:
(->> a (take 7) (drop 3)) ; get 4 elements starting from 3
(->> a (drop-last 3) (drop 3)) ; get all elements except the first and the last 3
我认为如果你只对列表应用两个操作,那么这两个方法都是非常易读的,但是如果你有一个长字符串,如take
,map
,filter
,{ {1}},drop
然后使用first
宏可以使代码更容易阅读,甚至可能更容易编写。
答案 1 :(得分:20)
Python的序列概念与Clojure非常不同。
在Python中,
在Clojure中,
Clojure中最接近Python列表的是vector。作为Adam Sznajder suggests,您可以使用subvec
对其进行切片,但不能像在Python中那样添加或删除切片。
subvec
是一个快速的常数时间操作,而drop
会让您为绕过的元素数量付出代价(take
会让您为遍历的元素付费,但这些是你感兴趣的人)。
你的例子变成......
(def a (vec (range 1 (inc 10))))
(subvec a 0 3)
; [1 2 3]
(subvec a 3)
; [4 5 6 7 8 9 10]
(subvec a 0 (- (count a) 3))
; [1 2 3 4 5 6 7]
(subvec a (- (count a) 3))
; [8 9 10]
(subvec a 3 (+ 3 4))
; [4 5 6 7]
(subvec a 3 (- (count a) 3))
; [4 5 6 7]
答案 2 :(得分:10)
有一个函数subvec
。不幸的是,它只适用于矢量,因此您必须转换序列:
答案 3 :(得分:6)
切片序列有点像代码气味" - 通常用于顺序访问项目的序列。
如果要进行大量的切片/连接,可以使用更好的数据结构,特别是检查RRB-Tree向量的实现:
这支持非常高效的subvec
和catvec
操作。