4.5 调用特定结构函数
Clojure包含一些专门针对列表lists,向量vectors,映射maps,结构structs和集合sets的函数
1. 针对列表Lists的函数
(peek coll) 获取列表第一个元素,(peek '(1 2 3)) 返回1
(pop coll) 获取除第一个元素外的其他元素,(pop '(1 2 3))返回(2 3)
说明:如果列表coll为空,则pop抛出异常
2. 针对向量vector的函数
(1) peek 获取向量最后一个元素,(peek [1 2 3]) 返回3
(2) pop 获取除最后一个元素外的其他元素,(pop [1 2 3]) 返回[1 2]
(3) get 获取指定索引位置的元素,如果索引超出范围,则返回nil,(get [:a :b :c] 1) 返回:b
(4) assoc 给指定索引赋值
(assoc [0 1 2 3 4] 2 :two) 返回[0 1 :two 3 4]
(5) subvec 返回向量的子向量
(subvec avec start end?) 如果end没指定则默认为向量结尾,(subvec [1 2 3 4 5] 3) 返回[4 5]
向量本身即函数,以索引为参数,返回指定位置的元素,如果索引参数超出返回,则抛出异常,如
user=> ([:a :b :c] 5)
java.lang.ArrayIndexOutOfBoundsException: 5 (NO_SOURCE_FILE:0)
3. 针对Map的函数
(1) (keys map) 返回map的key序列,(keys {:sundance "spaniel", :darwin "beagle"}),返回(:sundance :darwin)
(2) (vals map) 返回map的值序列,(vals {:sundance "spaniel", :darwin "beagle"}),返回("spaniel" "beagle")
(3) (get map key value-if-not-found?) 返回指定key对应的value,如果没有则返回nil或value-if-not-found
(get {:sundance "spaniel", :darwin "beagle"} :darwin) 返回"beagle"
(4) Map是它们key的函数,返回指定key对应的value值,类似get函数
({:sundance "spaniel", :darwin "beagle"} :darwin) 返回"beagle"
(5) 关键字Keywords 也是函数,以Map为参数,返回Map中Keywords对应的值
(:darwin {:sundance "spaniel", :darwin "beagle"}) 返回"beagle"
(6) (contains? map key) 判断map是否包含键为key的键值对元素
user=> (def score {:stu nil :joey 100})
user=> (:stu score) 返回nil
user=> (contains score :stu) 返回true
(7) Clojure还提供了几个创建新Map的函数:
assoc 返回一个添加新key/value对的map
dissoc 返回一个删除指定key对应的元素的map
select-keys 返回一个只包含传入key对应元素的map
merge 合并多个map
以下举例说明
user=> (def song {:name "Agnus Dei"
:artist "Krzysztof Penderecki"
:album "Polish Requiem"
:genre "Classical"})
#'user/song
user=> (assoc song :kind "MPEG Audio File")
{:kind "MPEG Audio File", :name "Agnus Dei", :artist "Krzysztof Penderecki", :al
bum "Polish Requiem", :genre "Classical"}
user=> (dissoc song :genre)
{:name "Agnus Dei", :artist "Krzysztof Penderecki", :album "Polish Requiem"}
user=> (select-keys song [:name :artist])
{:artist "Krzysztof Penderecki", :name "Agnus Dei"}
user=> (merge song {:size 8118166, :time 507245})
{:time 507245, :size 8118166, :name "Agnus Dei", :artist "Krzysztof Penderecki", :album "Polish Requiem", :genre "Classical"}
(8) (merge-with merge-fn & maps) 类似merge,但是针对相同key的元素值,通过函数merge-fn进行合并,如
user=> (merge-with concat {:rubble ["Barney"], :flintstone ["Fred"]} {:rubble ["Betty"], :flintstone ["Wilma"]}
{:rubble ["Bam-Bam"], :flintstone ["Pebbles"]})
{:rubble ("Barney" "Betty" "Bam-Bam"), :flintstone ("Fred" "Wilma" "Pebbles")}
4. 针对Sets的函数
Clojure提供的针对sets的函数都在clojure.set命名空间中
(1) 第一组函数来自集合理论中的运算
union 返回多个集合的并集
intersection 返回多个集合的交集
defference 返回集合的差集
select 返回满足谓词条件的元素组成的子集
下面举例说明
user=> (def languages #{"java" "c" "d" "clojure"})
user=> (def letters #{"a" "b" "c" "d" "e"})
user=> (def beverages #{"java" "chai" "pop"})
user=> (use 'clojure.set)
user=> (union languages beverages)
#{"java" "c" "d" "clojure" "chai" "pop"}
user=> (difference languages beverages)
#{"c" "d" "clojure"}
user=> (intersection languages beverages)
#{"java"}
user=> (select #(= 1 (.length %)) languages)
#{"c" "d"}
关系代数,数据库和clojure数据类型直接的对应关系如下表所示:
关系代数 数据库 clojure数据类型
关系 表 类似set的类型
元组 行 类似map的类型
关系代数包含六种基本的运算:并集,差集,选择,重命名,投影,交叉乘积。前三种上面已经介绍,下面看后三种。
(1) 重命名(rename relation rename-map),指重命令map的key(即数据库表的列名)
(2) 投影(project relation keys),类似SQL查询指定列子集,返回指定的key的key/value对
(3) 交叉乘积
通过for宏可以计算多个关系(即集合)的笛卡尔积
通过(join relation-1 relation-2 keymap?)中共同的key关联两个关系组成一个新的关系(类似数据库的自然连接),如果两个关系的key都不一致,可以通过keymap将relation-1中key名称与relation-2中对应key名称进行关联
下面举例说明:
定义关系(即map集合)
user=> (def compositions
#{{:name "The Art of the Fugue" :composer "J. S. Bach"}
{:name "Musical Offering" :composer "J. S. Bach"}
{:name "Requiem" :composer "Giuseppe Verdi"}
{:name "Requiem" :composer "W. A. Mozart"}})
user=> (def composers
#{{:composer "J. S. Bach" :country "Germany"}
{:composer "W. A. Mozart" :country "Austria"}
{:composer "Giuseppe Verdi" :country "Italy"}})
user=> (def nations
#{{:nation "Germany" :language "German"}
{:nation "Austria" :language "German"}
{:nation "Italy" :language "Italian"}})
重命名
user=> (rename compositions {:name :title})
#{{:title "The Art of the Fugue", :composer "J. S. Bach"}
{:title "Requiem", :composer "W. A. Mozart"}
{:title "Requiem", :composer "Giuseppe Verdi"}
{:title "Musical Offering", :composer "J. S. Bach"}}
投影
user=> (project compositions [:name])
#{{:name "Requiem"} {:name "The Art of the Fugue"} {:name "Musical Offering"}}
注意:"Requiem"重复,只保留一个
笛卡尔积
(for [m compositions c composers] (concat m c))
交叉乘积
user=> (join compositions composers)
#{{:name "Requiem", :composer "Giuseppe Verdi", :country "Italy"}
{:name "Musical Offering", :composer "J. S. Bach", :country "Germany"}
{:name "Requiem", :composer "W. A. Mozart", :country "Austria"}
{:name "The Art of the Fugue", :composer "J. S. Bach", :country "Germany"}}