Clojure中的习语序列片(Idiomatic sequence slice in Clojure

2019-07-31 03:01发布

在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.repl/doc Clojure中,我发现等同于所有的人,但我不知道他们是地道的。

(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中? 换句话说,什么是返回一个序列的不同部分的正确方法是什么?

Answer 1:

您可以简化使用所有那些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

我认为这两种方法都非常可读的,如果你只应用两个操作的列表,但是当你有长长的一串像takemapfilterdropfirst再使用->>宏可以使代码更容易阅读,甚至可能更容易编写。



Answer 2:

序列的Python的概念是从Clojure的很大的不同。

在Python,

  • 一个序列是一个有限有序集由非负数索引 ; 和
  • 列表是一个可变的序列,您可以从添加切片或删除片。

在Clojure中,

  • 一个序列是支持的接口firstrest ,和cons ;
  • 一个列表是不可变的有序集合以cons (或rest )添加(或去除) first元件(返回如此修改列表,反正)。

Clojure中的一个Python列表最近的东西是一个载体 。 正如亚当Sznajder建议 ,你可以使用切它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]


Answer 3:

还有一个功能subvec 。 不幸的是,它只能与载体的作品,所以你必须改变你的序列:

http://clojuredocs.org/clojure_core/clojure.core/subvec



Answer 4:

切片序列是一个有点“代码味道”的 - 一般的顺序是专为项目的顺序访问。

如果你打算做了很多切片/级联的,也有更好的数据结构可用,尤其是结账的RRB树向量执行:

  • https://github.com/clojure/core.rrb-vector

这支持非常有效subveccatvec操作。



文章来源: Idiomatic sequence slice in Clojure