Programming Clojure学习笔记——使用序列统一数据

来源:互联网 发布:保定软件技术学院电话 编辑:程序博客网 时间:2024/05/16 14:02
4.2 使用序列库
序列库函数可以分为以下四大类:
1. 创建序列函数
2. 过滤序列函数
3. 序列谓词
4. 序列转换函数
这种分类很粗糙,由于序列不可改变,因此大部分序列函数都创建新的序列,一些序列函数既有过滤也有转换功能。

1. 序列创建
(1) (range start? end step?) 创建一个从start到end,步长为step的序列,start默认为0,step默认为1.
(2) (repeat n x) 创建一个有n个x组成的序列
     (repeat x) 创建一个由无穷个x组成的无限序列
(3) (iterate f x) 通过不断迭代调用函数f,创建一个无限大的序列,如
user=> (take 10 (iterate inc 1))
(1 2 3 4 5 6 7 8 9 10)
说明:
(iterate inc 1) 创建一个从1开始直到无限大的序列
(take n sequence) 函数返回一个无限序列sequence的前n个元素

(4) (cycle coll) 创建一个由无限个集合coll组成的序列,序列的元素为集合coll中的元素
user=> (take 10 (cycle (range 3)))
(0 1 2 0 1 2 0 1 2 0)

(5) (interleave & colls) 依次从多个集合中取出元素,直到其中一个集合所有元素都被取完,生成一个新的集合
user=> (interleave '(1 2 3 4) ["a" "b"] '(A B C))
(1 "a" A 2 "b" B)

(6) (interpose separator coll) 创建一个由separator将集合coll中每两个元素隔开的序列
user=> (interpose "," ["apples" "bananas" "grapes"])
("apples" "," "bananas" "," "grapes")

(7) 对于Clojure中的每一个集合类型,都有一个对应的函数可以接受任意多个参数创建一个对应类型的集合
(list & elements)
(vector & elements)
(hash-set & elements)
(hash-map key-1 val-1 ...)
另外
hash-set有一个兄弟set,它接受一个集合参数,返回一个set
(set [1 2 3]) 与(hash-set 1 2 3) 等同
vector也有一个兄弟vec,它也接受一个集合参数,返回一个vector
(vec [0 1 2]) 与(vector 0 1 2) 等同

2. 序列过滤
(1) (filter pred coll) 返回集合中使得pred谓词返回true的元素组成的序列
user=> (filter even? [1 2 3 4 5])
[2 4]

(2) (take-while pred coll) 返回一个从集合元素开始直到第一个使得pred为false的元素(不包括该元素)为止的所有元素组成的集合
user=> (take-while even? [2 4 1 5 6])
(2 4)
说明:从第一个元素开始2,4都满足even?条件,但第三个不满足,因此就终止从集合中取元素,虽然第5个元素6也满足条件但只取到第三个就不继续取了,因此返回(2 4)

(3) (drop-while pred coll) 与take-while相反,去掉从头开始连续使得pred返回true的元素,然后返回剩下元素组成的集合
user=> (drop-while even? [2 4 1 5 6])
(1 5 6)

(4) (split-at index coll) 返回一个由集合coll从index位置分割成的两个集合组成的向量:
user=> (split-at 5 (range 10))
[(0 1 2 3 4) (5 6 7 8 9)]

(5) (split-with pred coll) 与split-at类似,返回一个以集合coll中满足pred条件的元素组成的集合和不满足pred条件的元素组成的集合为元素的向量
user=> (split-with #(<= % 10) (range 0 20 2))
[(0 2 4 6 8 10) (12 14 16 18)]

说明:take-,split-和drop-函数均返回懒序列

Programming Clojure学习笔记——使用序列统一数据
3. 序列谓词
序列谓词判断其他谓词应用于序列每一个元素的结果。
(1) (every? pred coll) 判断是否集合中每个元素都使pred返回true
user=> (every? odd? [1 3 5]) 返回true
user=> (every? odd? [1 3 5 8]) 返回false

(2) (some? pred coll) 返回第一个非false值,或者返回nil如果没有元素匹配
user=> (some even? [1 2 3]) 返回true
user=> (some even? [1 3 5]) 返回nil
说明:some不是谓词,它返回第一个匹配的实际值,不一定是true

(3) (not-every? pred coll) 判断是否不是所有的元素都使pred返回true
(4) (not-any? pred coll) 判断是否所有的元素都使pred返回false

4. 序列转换
转换函数转换序列中的值
(1) (map f coll) 返回以集合coll中每一个元素为参数调用函数f的结果组成的序列,集合的个数与函数f的参数个数一致,返回结果集合大小与最小集合大小一致
user=> (map #(format "<%s>%s" %1 %2 %1) ["h1" "h2" "h3" "h1"] ["the" "quick" "brown" "fox"])
("<h1>the</h1>" "<h2>quick</h2>" "<h3>brown</h3>" "<h1>fox</h1>")

(2) (reduce f coll)
f是一个两个参数的函数,reduce以集合coll开头两个元素为参数调用f函数,然后以函数结果及第三个元素为参数继续调用函数f,依次类推,直到最后一个元素,并返回最后依次函数的返回值
user=> (reduce + (range 1 11)) 等同1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10
55

(3) (sort comp? coll)和(sort-by a-fn comp? coll)
sort没有比较函数comp则按自然顺序排列集合元素,sort-by则对每一个元素调用函数a-fn,然后对函数执行结果进行排序。
sort和sort-by如果有比较函数参数,则按函数指定的方式进行排序
user=> (sort > [42 1 7 11])
(42 11 7 1)
user=> (sort < [42 1 7 11])
(1 7 11 42)

列表解析
Clojure中列表解析使用for宏:
(for [binding-form coll-expr filter-expr? ...] expr)
user=> (for [word ["the" "quick" "brown" "fox"]]
              (format "<p>%s</p>" word))
("<p>the</p>" "<p>quick</p>" "<p>brown</p>" "<p>fox</p>")

使用:when语句可以模拟filter函数:
user=> (defn whole-numbers [] (iterate inc 1))
#'user/whole-numbers
user=> (take 10 (for [n (whole-numbers) :when (even? n)] n))
(2 4 6 8 10 12 14 16 18 20)
使用:while语句可以模拟take-while函数:
user=> (for [n (whole-numbers) :while (odd? n)] n)
(1)

for宏还能有多个绑定表达式,解析时针对多个表达式的笛卡尔乘积进行。如:
user=> (for [rank (range 1 4) file "ABCD"] (format "%c%d" file rank))
("A1" "B1" "C1" "D1" "A2" "B2" "C2" "D2" "A3" "B3" "C3" "D3")
原创粉丝点击