常用函数
1 conj(连词)
往瞬态集合中添加X
(conj [1 3 4]5)
=>[1 3 4 5]
2 recur复发
尾递归的时候的时候用着,recur会将一个尾递归转换为一个不需要消耗栈的循环.
recur调用循环使用新值,loop是recur的递归点
3 first和rest
first(返回第一项)和 rest(返回集合中第一项之后的其余项)
4 reduce-kv
结构:(reduce-kv f init coll)
=>(reduce-kv 函数 初始值 操作序列)
- 函数接受的参数可以是
向量或者多个列表,但是他们的fn的值不一样
reduce-kv 和assoc 组合使用
例1.把矢量中的中每一个清单中的每一项数据都进行 +1
;;定义需要操作的数据
(def vector-of-maps [{:a 1 :b 2} {:a 3 :b 4}])
;;定义一个函数,进行数据+1操作
(defn update-map [m f]
(println "===="m "*******" f)
(reduce-kv (fn [m k v] ;; k表示key,v表示value
(println "===="m "*******" k "&&&&&&" v)
(assoc m k (f v))) {} m))
;;调用函数
(map #(update-map % inc) vector-of-maps)
打印函数数据的解析过程:
(map #(update-map % inc) vector-of-maps)
==== {:a 1, :b 2} ******* #object[clojure.core$inc 0x60a91f0 clojure.core$inc@60a91f0]
==== {} ******* :a &&&&&& 1
==== {:a 2} ******* :b &&&&&& 2
==== {:a 3, :b 4} ******* #object[clojure.core$inc 0x60a91f0 clojure.core$inc@60a91f0]
==== {} ******* :a &&&&&& 3
==== {:a 4} ******* :b &&&&&& 4
=> ({:a 2, :b 3} {:a 4, :b 5})
例2:两个清单A,B,若B清单和A清单有相同的key,则把A清单中key对应的值换成B中的,若key不同,则把k-v放入到A清单中,组装成新的清单
(reduct-kv fn m e) =>m是初始值,e是操作序列
(defn update-map-entries[m e]
(println "======="m "&&&&&&" e)
(reduce-kv (fn [r k v ] ;;r对应的是第一个{}, k和v是从第二个{}中找
(println "######"r "&&&&&&" k "====="v)
(assoc r k v)) m e))
函数数据解析:
(update-map-entries {:a 1 :b 2 :c 3} {:a 5 :b 9})
======= {:a 1, :b 2, :c 3} &&&&&& {:a 5, :b 9}
###### {:a 1, :b 2, :c 3} &&&&&& :a ===== 5
###### {:a 5, :b 2, :c 3} &&&&&& :b ===== 9
=> {:a 5, :b 9, :c 3}
(update-map-entries {:a 1 :b 2 :c 3} {:a 5 :b 9 :d 8})
=> {:a 5, :b 9, :c 3, :d 8}
5 mapv
结构:(mapv f coll)(mapv f c1 c2)(mapv f c1 c2 c3)(mapv f c1 c2 c3 & colls)
mapv 把
6 merge 合并
返回一个映射,其中包含其他映射到的映射
首先。如果一个键出现在多个映射中,则映射来自
后者(从左到右)将是结果中的映射。
;; :b键重复多次,最后的结果是从左向右的后者
(merge { :a 1 :b 2 :c 3 } { :b 9 :d 4 } );; => {:d 4,:a 1,:b 9,:c 3}
7 even? (是否为偶数) odd? (是否为基数)
(even? 2) ===>true
(odd? 3)>true
8 range (范围)
(range 5) ===>(1 2 3 4)
(range 8)===>(1 2 3 4 5 6 7)
9 select-keys
结构:(select-keys map keyseq)
例子:选出map中 :a :c 键所对应的key value值
user=> (select-keys {:a 1 :b 2 :c 3} [:a :c])
{:c 3, :a 1}
10 group-by (分组)
结构:(group-by f coll)
按某个键进行分组,把某个键的值提出来
例子:
(group-by :user-id [{:user-id 1 :uri "/"}
{:user-id 2 :uri "/foo"}
{:user-id 1 :uri "/account"}])
;; 按:user-id进行分组,把:user-id的值提出来
;;=> {1 [{:user-id 1, :uri "/"}
;; {:user-id 1, :uri "/account"}],
;; 2 [{:user-id 2, :uri "/foo"}]}
注:
单纯的用group by进行分组,只是把key对应的value提出来,有时候满足不了我们的需求,我们需要把 整个key-value 提出来,这个时候还需要一个函数,组合使用才能完成。一般用group by 和select-keys 进行分组过滤
定义函数:
(defn grouped-by-keys
([data group-keys]
(->> data
(group-by (fn [m] (select-keys m group-keys))))))
;;开始调用函数
(grouped-by-keys entries1 [:val])
;;结果
=>
{{:val "hello"} [{:month 1, :val "hello", :s1 true, :s2 false}
{:month 9, :val "hello", :s1 true, :s2 false}
{:month 10, :val "hello", :s1 true, :s2 false}],
{:val "nam"} [{:month 2, :val "nam", :s1 false, :s2 true}
{:month 7, :val "nam", :s1 false, :s2 true}
{:month 8, :val "nam", :s1 true, :s2 false}],
{:val "cx"} [{:month 3, :val "cx", :s1 true, :s2 false}
{:month 4, :val "cx", :s1 true, :s2 false}
{:month 5, :val "cx", :s1 false, :s2 true}
{:month 6, :val "cx", :s1 false, :s2 true}],
{:val "font"} [{:month 11, :val "font", :s1 false, :s2 true} {:month 12, :val "font", :s1 false, :s2 true}]}
观察结果,感觉这样的结果看起来很别扭,希望把分组后的孩子们中的:val 都去掉,并且把孩子们放入到list,这样让人看起来比较直观易懂,把之前的函数改一改:
;;定义函数
(defn grouped-by-keys
([data group-keys]
(->> data
(group-by (fn [m] (select-keys m group-keys)))
+ (reduce-kv (fn [m k v]
+ (assoc m k {:list
+ (mapv
+ (fn [e]
+ (apply dissoc e group-keys))
+ v)}))
+ {}))))
调用函数,结果发生变化
;;结果
=>
{{:val "hello"} {:list [{:month 1, :s1 true, :s2 false}
{:month 9, :s1 true, :s2 false}
{:month 10, :s1 true, :s2 false}]},
{:val "nam"} {:list [{:month 2, :s1 false, :s2 true} {:month 7, :s1 false, :s2 true} {:month 8, :s1 true, :s2 false}]},
{:val "cx"} {:list [{:month 3, :s1 true, :s2 false}
{:month 4, :s1 true, :s2 false}
{:month 5, :s1 false, :s2 true}
{:month 6, :s1 false, :s2 true}]},
{:val "font"} {:list [{:month 11, :s1 false, :s2 true} {:month 12, :s1 false, :s2 true}]}}
通过一次润色之后,这个结果看起来很简单、易懂、直观,但是认证看,发现内容的最外层是用一个{}括起来的,现在希望换成用一个[括起来],增加一行代码:
;;定义函数
(defn grouped-by-keys
([data group-keys]
(->> data
(group-by (fn [m] (select-keys m group-keys)))
(reduce-kv (fn [m k v]
(assoc m k {:list
(mapv
(fn [e]
(apply dissoc e group-keys))
v)}))
{})
+ (mapv (fn [e] (apply merge e))))))
结果:
;;调用函数
(grouped-by-keys entries1 [:val])
;;结果
=>
[{:val "hello",
:list [{:month 1, :s1 true, :s2 false} {:month 9, :s1 true, :s2 false} {:month 10, :s1 true, :s2 false}]}
{:val "nam", :list [{:month 2, :s1 false, :s2 true} {:month 7, :s1 false, :s2 true} {:month 8, :s1 true, :s2 false}]}
{:val "cx",
:list [{:month 3, :s1 true, :s2 false}
{:month 4, :s1 true, :s2 false}
{:month 5, :s1 false, :s2 true}
{:month 6, :s1 false, :s2 true}]}
{:val "font", :list [{:month 11, :s1 false, :s2 true} {:month 12, :s1 false, :s2 true}]}]
现在结果看起来就很舒服了。
11 匿名函数
我们可以通过fn来声明一个匿名函数
user=> ((fn [name] (str "hello " name)) "world")
"hello world"
我们也可以通过def来给一个匿名函数设置名称:
user=> (def a (fn [name] (str "hello " name)))
#'user/a
user=> (a "world")
"hello world"
我们使用 % 来表明匿名函数的参数,如果有多个参数,则使用 %1 , %2 来获 取,使用 %& 来获取可变参数。
user=> (#(str "hello " %) "world")
"hello world"
user=> (#(str "hello " %1 " " %2) "world" "a ha")
"hello world a ha"
user=> (#(str "hello " %1 " " (clojure.string/join " " %&)) "world" "ha" "ha")
"hello world ha ha"