轨道
/
Common Lisp
Common Lisp
/
练习
/
Leslie 的超长列表
Leslie 的超长列表

Leslie 的超长列表

学习练习

简介

列表

考虑到我们使用的语言 Lisp 的名字是 LIST Processing(列表处理)的缩写,你可能会以为它具备处理元素列表的功能,而你想得没错!

虽然 Common Lisp 还有列表以外的其他数据结构,但列表的使用仍然非常普遍。

Common Lisp 中的列表是元素的序列。它也被称为cons(主要是出于历史原因)。 元素本身的类型不必相同。 例如,你可以有一个包含1、two、"III"的列表。

创建列表

你可以直接输入一个带引号的列表,像这样:'(1 two "III"),这样就会创建并求值一个列表(求值结果为(1 two "III"))。

另外还有两个用于创建列表的主要函数:list和cons。

list接受零个或多个实参,求值结果是一个由这些值创建的列表:

(list 1 'two "III") ; => (1 two "III")

cons接受两个元素,创建一个列表,第一个元素作为它的car(列表的头部),第二个元素作为它的cdr(列表的剩余部分):

(cons 1 2)            ; => (1 . 2) ;; (a list without `nil` as its `cdr` is printed in this way)
(cons 1 nil)          ; => (1)
(cons 1 (cons 2 nil)) ; => (1 2)

函数car和cdr可以用来访问列表的car和cdr。

(first和rest是car和cdr的同义词,作用完全相同。)

长度与随机访问

列表的长度可以用length求得。 空列表的长度为零。

可以用nth访问任意一个元素(注意,列表的下标从 0 开始)。

请求一个大于列表长度的下标并_不_是错误,它反而会求值为nil:

(nth 23 '(short list)) ; => nil

此外还有几个辅助方法可以访问列表的前几个元素:first、second、third,一直到tenth。很妙吧?

合并列表

两个或多个列表可以用append合并:

(append '(a b c) '(1 2 3)) ; => (A B C 1 2 3)
(append '(a b c) '())     ; => (A B C)

传给append的每个实参都必须是列表。

说明

Lisp 外星人 Leslie 要去购物了。有一份购物清单非常重要。你需要往上面添加物品,也要从上面移除物品。

当然,区区纸笔可满足不了 Lisp 外星人。要知道,“list”几乎就是“Lisp”这个词的大半!总得写几个函数来帮忙管理购物清单。

你能帮 Leslie 管理这份购物清单吗?

1. 创建一个新列表

首先,Leslie 需要创建一个空列表。一个叫new-list的函数就再合适不过了。

(new-list) ; => ()

哦不……Leslie 心里已经想好了几样东西,所以还需要一个接收 3 个物品的函数(好在 Leslie 只会创建 3 个物品的列表。不多不少!),用它创建一份装着这些东西的新购物清单。写一个函数list-of-things,它接收 3 个物品,返回由这些物品组成的列表。

(list-of-things 'bread 'milk 'butter) ; => '(bread milk butter)

2. 往列表里添加东西。

去商店之前,Leslie 会先看看食品储藏室里有什么,确认自己还缺什么。请帮他们写一个函数add-to-list,它会把物品添加到列表的开头。

(add-to-list 'butter '(bread)) ; => '(butter bread)

3. 列表上接下来要买的是什么?

购物时,Leslie 想知道接下来该找什么。他们还喜欢往列表后面瞄一眼,看看第 2 个、第 3 个,甚至第 23 个物品(那是他们的幸运数字)。

  • first-thing会求值为列表上的第 1 个物品
  • second-thing会求值为第 2 个物品
  • third-thing会求值为第 3 个物品
  • twenty-third-thing会求值为第 23 个物品
(first-thing '(bread butter milk)) ; => 'bread
(second-thing '(bread butter milk)) ; => 'butter
(third-thing '(bread butter milk)) ; => 'milk

4. 从列表中移除物品

Leslie 想找到列表中的第 1 个物品,并把它从货架上取下来。请帮他们写一个函数remove-first-item,它的求值结果是输入列表中除第 1 个物品之外的所有物品组成的列表。

(remove-first-item '(bread butter milk)) ; => '(butter milk)

5. 用更小的列表拼出更大的列表

Leslie 发现自己不小心做了 2 份购物清单,而不是 1 份!写一个函数list-append,它返回的列表中,先是第一个列表里的元素,接着是第二个列表里的元素。

(list-append '(bread salt) '(butter milk)) ; => '(bread salt butter milk)

6. 到底有多长?

Leslie 开始担心这趟购物会花上不少时间。这个列表上到底有多少物品?写一个函数just-how-long,告诉他们列表有多长。

(just-how-long '(bread milk butter salt)) ; => 4
通过 GitHub 编辑 链接将在新窗口或新标签页中打开
Common Lisp Exercism

准备好开始 Leslie 的超长列表 了吗?

注册 Exercism,借助 27 个概念92 个练习 和真人导师指导,学习并掌握 Common Lisp,全部免费。