您的位置:首页 > 其它

LISP 向量

2013-12-07 21:07 337 查看

Lisp笔记:集合

---------集合是把人们的直观的或思维中的某些确定的能够区分的对象汇合在一起,使之成为一个整体(或称为单体),这一整体就是集合。组成一集合的那些对象称为这一集合的元素(或简称为元)。(取自百度百科)





基本的集合类型通常都可以归结为一个整数索引的数组类型(如数组,列表,元组),以及一个可将或多或少的任意关键字映射到值上的表类型(如哈希表,关联数组,映射表,字典)。

向量:

1) 向量是Common Lisp基本的整数索引集合,分为定长向量和变长向量。使用VECTOR生成定长向量。

(vector) --> #()
(vector 1) --> #(1)
(vector 1 2) --> #(1 2)


但MAKE-ARRAY更为通用和方便

(make-array 5 :initial-element nil) -> #(nil nil nil nil nil)


MAKE-ARRAY用来创建变长向量

(make-array 5 :fill-pointer 0)(只能存5个元素)这个创建了5个位置用来存放,每存放一个,填充指针的当前值上添加一个元素并将填充指针递增一次。可以使用VECTOR-PUSH和VECTOR-POP。

但是带有一个填充指针的向量也不是完全变长的,为了创建可任意变长的,可以用:adjustable. 如(make-array 5 :fill-pointer 0 :adjustable t) -> #()

2)向量的子类型

特化向量:仅限于保存特定类型的元素。它们可以更加紧凑的存储,并且可以比通用向量提供对其元素更快速的访问。 创建一个初始化为空但却变长的字符串。

(make-array 5 :fill-pointer 0 :adjustable t :element-type ‘character) -> “”

3)序列函数

LENGTH,ELT

(defparameter *x* (vector 1 2 3))
(length *x*) -> 3
(elt *x* 2) -> 3
(elt *x* 3) -> error
如setf: 	(setf (elt *x* 0) 10)   *x* -> #(10 2 3)


理论上所有的序列操作都可归结于LENGTH,ELT和ELT,SETF操作的某种组合,但Common Lisp还是提供了一个庞大的序列函数库。

名称

所需参数

返回

COUNT

项和序列

序列中出现某项的次数

FIND

项和序列

项或nil

POSITION

项和序列

序列中的索引nil

REMOVE

项和序列

项的实例被移除后的序列

SUBSTITUTE

新项,项和序列

项的实例被新项替换后的序列

参数

含义

默认值

:test

两参数函数用来比较元素和项

EQL

:key

单参数函数用来从实际的序列元素中解出用于比较关键字值nil表示原样采用序列元素

NIL

:start

子序列的起始索引(含)

0

:end

子序列的终止索引(不含)。Nil表示到序列的结尾

Nil

:from-end

如果为真序列将以相反的顺序遍历,从尾到头

Nil

:count

数字代表需要移除或替换的元素个数,nil代表全部。仅用于(REMOVE和SUBSTITETE)

nil

(count 1 #(1 2 1 2 1 3 1 2 3 4)) -> 3
(remove 1 #(1 2 1 2 3 1 2 3 4)) -> #(2 2 3 2 3 4)
(remove 1 ‘(1 2 1 2 3 1 2 3 4)) -> (2 2 3 2 3 4)
(remove #\a “foobarbaz”) -> “foobrbz”
(substitute 10 1 #(1 2 1 2 3 1 2 3 4)) -> #(10 2 10 2 3 10 2 3 4)
(substitute 10 1 ‘(1 2 1 2 3 1 2 3 4)) -> (10 2 10 2 3 10 2 3 4)
(substitute #\x #\b “foobarbaz”) -> “fooxarxaz”
(find 1 #(1 2 1 2 3 1 2 3 4)) -> 1
(find 10 #(1 2 1 2 3 1 2 3 4)) -> nil
(position 1 #(1 2 1 2 3 1 2 3 4)) -> 0
(注意:REMOVE和SUBSTITUTE总是返回于其序列实参相同类型的序列)
(count “foo” #(“foo” “bar” “baz”) #’string=) -> 1
(find ‘c #((a 10) (b 20) (c 30) (d 40)) :key #’first) -> (c 30)
(find ‘a #((a 10) (b 20) (a 30) (b 40)) :key #’first) -> (a 10)
(find ‘a #((a 10) (b 20) (a 30) (b 40)) :key #’first :from-end t) -> (a 30)
(remove #\a “foobarbaz” :count 1) -> “foobrbaz”
(remove #\a “foobarbaz” :count 1 :from-end t) -> “foobarbz”


4)高阶函数变体:

刚刚讨论过的函数,Common Lisp都提供了两种高阶函数变体,它们接受一个将在每个序列元素上调用的函数,以此来代替项参数。

一组变体被命名为与基本函数相同的名字并带有一个追加的-IF,这些函数用于计数,查找,移除以及替换序列中那些函数参数返回真的元素,以-IF-NOT则相反。

(count-if #’evenp #(1 2 3 4 5)) -> 2	(evenp求偶数)
(count-if-not #’evenp #(1 2 3 4 5)) -> 3
(position-if #’digit-char-p “abcd0001”) -> 4
(remove-if-not #'(lambda (x) (char= (elt x 0) #\f)) #("foo" "bar" "baz")) ->#(“foo”)
(count-if #'evenp #((1 a) (2 b) (3 c) (4 d) (5 e)) :key #'first) -> 2
(count-if-not #'evenp #((1 a) (2 b) (3 c) (4 d) (5 e)) :key #'first) -> 3
(remove-if-not #'alpha-char-p #("foo" "bar" "1baz") :key #'(lambda (x) (elt x 0))) -> #(“foo” “bar”)


移除所有重复元素

(remove-duplicates #(1 2 1 2 3 1 2 3 4)) -> #(1 2 3 4)


Concatenate被显式指定产生何种类型的序列,并创建将任意数量序列连接在一起的新序列。

(concatenate 'vector #(1 2 3) '(4 5 6) '(1 2 3)) -> #(1 2 3 4 5 6 1 2 3)
(concatenate 'list #(1 2 3) '(4 5 6)) -> (1 2 3 4 5 6)
(concatenate 'string "abc" '(#\d #\e #\f)) -> "abcdef"


SORT和 STABLE区别是STABLE-SORT保证不会重排任何被该谓词视为等价的元素。(具有破坏性)

(setf my-sequence (sort my-sequence #’string<)) 而不只是这样:
(sort my-sequence #’string<)


SUBSEQ它解出序列中从一个特定索引开始并延续到一个特定终止索引或结尾处的子序列。

(subseq “foobarbaz” 3) -> “barbaz”
(subseq “foobarbaz” 3 6) -> “bar”
(defparameter x (copy-seq “foobarbaz”))
(setf (subseq x 3 6) “xxx”)   x -> “fooxxxbaz”
(setf (subseq x 3 6) “abcd”)	x -> “fooabcdaz”
(setf (subseq x 3 6) “xx”)	x-> “fooxxcbaz”
(position #\b “fobarbaz”) -> 3
(search “bar” “foobarbaz”) -> 3


MISMATCH找出两个带有相同前缀的序列首次分岔的位置。

(mismatch "foobarbaz" "foorm") -> 3

(mismatch "foobar" "bar" :from-end t) ->3 表示两个序列的相同后缀在第一个序列中的开始位置。(mismatch "fooqqbar" "asdasdasdasdabar" :from-end t) -> 5

序列谓词:EVERY,SOME,NOTANY,NOTEVERY

(every #’evenp #(1 2 3 4 5)) -> nil
(some #’evenp #(1 2 3 4 5)) -> t


5)序列映射函数

MAP函数接受一个n-参数函数和n个序列,需要被告知其所创建序列的类型。

(map 'vector #'* #(1 2 3 4 5) #(10 9 8 7 6 3 4)) -> #(10 18 24 28 30)


MAP-INTO将几个向量a,b,c相加到一个向量里,(map-into a #’+ a b c)

REDUCE映射到单个序列上

(reduce #'+ #(1 2 3 4 5 6 7 8 9 10)) -> 55


REDUCE函数非常有用,当需要将一个序列提炼成一个单独的值时,你都有机会用REDUCE来写它,而这通常是一种相当简洁的表达意图的方法。

6)哈希表

哈希表允许你使用任意对象作为索引或是键(key).MAKE-HASH-TABLE创建哈希表

(defparameter *h* (make-hash-table))
(gethash 'foo *h*) -> nil
(setf (gethash 'foo *h*) 'haha) -> HAHA
(gethash 'foo *h*) -> HAHA	T


由于当键在表中不存在时GETHASH返回NIL,所以无法从返回值中看出,究竟是键在哈希表中不存在还是键在表中存在并带有值nil。GETHASH用一个特性解决了这一问题,即多重返回值(NIL 和 T)。

接下来我门使用MULTIPLE-VALUE-BIND宏来利用GETHASH额外返回值。

(defun show-value (key hash-table)
(multiple-value-bind (value present) (gethash key hash-table)
(if present
(format nil "value ~a actually present." value)
(format nil "value ~a because key not found." value))))
(setf (gethash 'bar *h*) nil)
(show-value 'foo *h*) -> "value HAHA actually present."
(show-value 'bar *h*) -> "value NIL actually present."
(show-value 'baz *h*) -> "value NIL because key not found."


移除键值对 (remhash 'foo *h*) -> T.

哈希表迭代:

MAPHASH接受一个有两个参数的函数和一个哈希表,并在哈希表的每一个键值对上调用一次该函数。例如,打印哈希表中所有键值对:

(maphash #'(lambda (k v) (format t "~a => ~a~%" k v)) *h*)


等价于(LOOP形式)

(loop for k being the hash-keys in *h* using (hash-value v)
do (format t "~a => ~a~%" k v))


移除其值小于10的项

(maphash #’(lambda (k v) (when (< v 10) (remash k *h*))) *h*)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: