• Clojure学习03:数据结构(集合)


    Clojure提供了几种强大的数据结构(集合)

    一、集合种类

    1、vector

    相当于数组,如: [2  3   5]  ,  ["ad"  "adas"  "adadsads"]

    2、list

    相当于链表,如: '(2  3   5)  ,  '("ad"  "adas"  "adadsads")

    与vector相比,[]变成了() ,又因为 ()符号是用于函数调用,为了区别,需要在 ( 前面加上  一个单引号'

    3、map

    语法格式如: {:a  1  :b  1} 

    map是1个或多个 key-value对,其中key标识符前面要求有:标识 。map的key本身就是函数,通过它可以查找它所对应的值。

    如:

    user=> (def data {:a 1 :b 2} )
    
    user=> (:a data)
    1
    user=> (:a {:a 1 :b 2} )
    1
    user=> (:a {:a 3 :b 2} )
    3

    上面第一个语句定义了一个值data,是个map。 第二个语句是获取关键字:a的值,这里:a就是一个函数。
    最后两个语句就是直接从map字面量上查询key对应的值。

    4、set

    语法格式如: #{值1  值2  ....}

    user=> #{1 2 3}
    #{1 3 2}

    说明,相比java的集合,Clojure的集合对象有如下几个特征:

    1) immutable  集合的内容在初始化后是不可修改的,后续对它的操作都会产生新的集合

    2)heterogeneous  多相(异种的),集合中的元素不要求必须是同一种数据类型,可以是不同类型数据的集合

    3)persistent 持久化的,集合的内容是不可修改的,相关的操作会产生新的集合,但并不是复制的方式,而是有点类似配置管理的机制,只是新增变更的部分,老的部分还是采用原来的数据。这样所有的历史数据都能完整的保留下来。

    二、集合的三大操作

    所有函数式编程语言,都对集合的操作提供了一些基础的高阶函数,最典型的是  filter ,map 和 reduce三个函数。

    这个三个函数高度概括了对集合的操作。

    下面我们分别介绍。

    1、filter函数

    filter函数是函数式编程中对集合操作的三大重要操作之一,几乎所有的支持函数式编程的语言都有类似的方法。

    其作用是筛选出满足条件的元素组成一个新的集合返回。

    filter函数需要两个参数,第一个是过滤函数,用于检查元素是否符合,第二个是集合本身。结果返回一个list。

    如下面例子:

    例1:

    user=> (def stooges ["Moe" "Larry" "Curly" "Shemp"])
    #'user/stooges
    user=> (filter #(> (count %) 3) stooges)
    ("Larry" "Curly" "Shemp")

    上面代码中的count函数是计算字符串的长度, #(> (count %) 3) 是个匿名函数,只有长度大于3的字符串才满足条件。

    例2:

    user=> (def years [1940 1944 1961 1985 1987])
    #'user/years
    user=> (filter #(even? %) years)
    (1940 1944)

    2、map

    map函数是函数式编程中对集合操作的三大重要操作之一,几乎所有的支持函数式编程的语言都有类似的方法。

    其作用是 对集合中的每一个元素做处理,最后得到一个新的集合(注意集合类型是列表),新集合的元素个数和原集合一样,但内容可以不一样(包括元素的类型)。

    所以map函数 的第一个参数是对元素转换的处理函数,后面的参数是待处理的集合(一个或多个)。

    下面我们举例来说明:

    例1:

    (defn fun [item] (* item 2))   //定义了一个函数,返回的值是对输入参数乘以2

    (map fun [1 2 3])   //map函数使用了fun函数,最后map函数调用后的返回结果为 (2 4 6)

    可以看出,被处理的集合是vector,但处理后返回的集合类型为list

    例2:

    user=> (map fun #{1 2 3}) (2 6 4)

    可以看出,set被处理后返回的集合类型也是列表,而且因为set本身是无序的,返回的list结果序号与set表面上看的也不一致。

    例3:

    user=> (map + [2 4] [5 6] [1 2]) (8 12)

    user=> (map + [2 4 7] [5 6] [1 2 3 4]) (8 12)

    上面两个例子传入的第一个参数是函数是 + , 后面是多个集合。最后的结果是按照最小的集合元素算的。

    例4:

    user=> (map #(* % 2) [1 2 3]) (2 4 6)

    上面代码中传给map的是一个匿名函数  #(* % 2) 。在实际的集合map操作中,大量场景下会传入匿名函数。

    Clojure中的匿名函数就类似于 python、java8中的lambda表达式。

    3、reduce

    reduce函数是函数式编程中对集合操作的三大重要操作之一,几乎所有的支持函数式编程的语言都有类似的方法。

    其作用是对集合做处理,得到一个计算后的值。 如sum ,count, max, min 都是reduce操作的特例,只不过这些操作是非常常见和通用的 ,会被提为专门的方法。

    如:

    user=> (reduce #(+ %1 %2) [1 2 3])
    6

    上面操作是对集合求和。reduce的第一个参数是一个函数,这里是匿名函数,该匿名第一个参数(用1%代替)是每次迭代的返回值,%2是元素。

    每次对元素操作,1%都会重新最后作为参数传入,最后一个元素处理完后%1的值会作为reduce的函数值返回。

    user=> (reduce #(* %1 %2) [2 4 6])
    48

    上面操作是对集合中的元素求乘积。

    user=> (reduce #(if (> %1 %2) %1 %2) [10 2 54 3 6])
    54
    user=> (reduce #(if (< %1 %2) %1 %2) [10 2 54 3 6])
    2

    上面的两个操作分别是取最大值和最小值。

    三、集合的其它操作

    下面介绍的集合的操作都是对上述三大操作的一些特例。

    1、count函数

    该函数用于获取集合中的元素个数

    user=> (count [19 "yellow" true])
    3
    user=> (count '(19 "yellow" true))
    3
    user=> (count #{19 "yellow" true})
    3
    user=> (count {:a 1 :b 2})
    2

    从上面例子可以看出,count函数对这四种集合都是适合的。

    2、reverse

    该函数是对集合中的数据进行反转排列,返回一个新的集合。因为map和set本身是无序的数据结构,所以reverse函数也只对vector和list有意义。

    user=> (reverse [2 4 7])
    (7 4 2)
    user=> (reverse '(2 4 7))
    (7 4 2)

    3、map

    map函数的作用是 对集合中的每一个元素做处理,最后得到一个新的集合(注意集合类型是列表),新集合的元素个数和原集合一样,但内容可以不一样(包括元素的类型)。

    所以map函数 的第一个参数是对元素转换的处理函数,后面的参数是待处理的集合(一个或多个)。

    下面我们举例来说明:

    例1:

    (defn fun [item] (* item 2))   //定义了一个函数,返回的值是对输入参数乘以2

    (map fun [1 2 3])   //map函数使用了fun函数,最后map函数调用后的返回结果为 (2 4 6)

    可以看出,被处理的集合是vector,但处理后返回的集合类型为list

    例2:

    user=> (map fun #{1 2 3})
    (2 6 4)

    可以看出,set被处理后返回的集合类型也是列表,而且因为set本身是无序的,返回的list结果序号与set表面上看的也不一致。

    例3:

    user=> (map + [2 4] [5 6] [1 2])
    (8 12)

    user=> (map + [2 4 7] [5 6] [1 2 3 4])
    (8 12)

    上面两个例子传入的第一个参数是函数是 + , 后面是多个集合。最后的结果是按照最小的集合元素算的。

    例4:

    user=> (map #(* % 2) [1 2 3])
    (2 4 6)

    上面代码中传给map的是一个匿名函数  #(* % 2) 。在实际的集合map操作中,大量场景下会传入匿名函数

    Clojure中的匿名函数就类似于 python、java8中的lambda表达式。

    4、apply

    该函数的作用是给它传入一个函数和集合,该函数对整个集合进行操作后返回的结果就是apply函数的返回结果。

     user=> (apply + [2 4 6])
    12
    user=> (apply * [2 4 6])
    48
    user=> (apply - [2 4 6])
    -8

    5、从集合中获取单个元素

    user=> (def stooges ["Moe" "Larry" "Curly" "Shemp"])
    #'user/stooges
    user=> (first stooges)
    "Moe"
    user=> (second stooges)
    "Larry"
    user=> (last stooges)
    "Shemp"
    user=> (nth stooges 2)
    "Curly"

    最后一个方法nth的第2个参数表示获取第几个元素(从0开始,这里2代表第3个元素)。

    6、从集合中获取多个元素

    user=> (def stooges ["Moe" "Larry" "Curly" "Shemp"])
    #'user/stooges


    user=> (next stooges)
    ("Larry" "Curly" "Shemp")

    user=> (nthnext stooges 1)
    ("Larry" "Curly" "Shemp")

    user=> (nthnext stooges 2)
    ("Curly" "Shemp")
    user=> (butlast stooges)
    ("Moe" "Larry" "Curly")

    user=> (drop-last 1 stooges)
    ("Moe" "Larry" "Curly")
    user=> (drop-last 2 stooges)
    ("Moe" "Larry")

    7、some

    该函数可以用来判断集合中是否包含某个元素,需要一个用来判断的函数作为参数,另一个参数是集合本身。如:

    user=>  (def stooges ["Moe" "Larry" "Curly" "Shemp"])
    #'user/stooges
    user=> (some #(= % "Moe") stooges)
    true
    user=> (some #(= % "Mark") stooges)
    nil

    可以看出,如果存在则返回true,否则返回nil(为何不返回false呢?)。

    上面的写法会看起来比较笨拙,可以用如下的方法达到同样目的:

    user=> (contains? (set stooges) "Moe")
    true
    user=> (contains? (set stooges) "Mark")
    false

    上面操作,利用set方法将vector转换为set集合,然后利用contains?函数进行判断,看上去会更清晰简单些。

    另外一个区别是,当元素不存在时返回的不是nil,而是false

  • 相关阅读:
    Microsoft .NET Framework v4.0 正确安装方法
    彻底解决C#实现DataTable导出EXCEL表格
    利用log4net记录操作日志
    [转]驱动程序开发—编译正传(5)
    [转]驱动程序开发-概述(1)
    论富客户端程序的webservice实现
    在Vista中编程控制防火墙设定(C#)
    [转]驱动程序开发—编译前传(4)
    C#系统较时
    [转]驱动程序开发—工具篇(2)
  • 原文地址:https://www.cnblogs.com/51kata/p/5443762.html
Copyright © 2020-2023  润新知