List入门
在 Haskell 中,List同现实世界中的购物单一样重要。它是最常用的数据结构,并且十分强大,灵活地使用它可以解决掉很多问题。在本节,我们将对List,字符串和list comprehension有个初步了解。
在 Haskell 中,List是一种单类型的数据结构,可以用来存储多个类型相同的元素。我们可以在里面装一组数字或者一组字符,但不能字符和数字装在一起。
note:在ghci下,我们可以使用let关键字来定义一个常量。在ghci下执行let a =1与在脚本中编写a=1是等价的。
ghci>
let lostNumbers
= [
4 ,
8 ,
15 ,
16 ,
23 ,
48 ]
![BUY A DOG](http://learnyouahaskell.com/list.png)
在 Haskell 中,List同现实世界中的购物单一样重要。它是最常用的数据结构,并且十分强大,灵活地使用它可以解决掉很多问题。在本节,我们将对List,字符串和list comprehension有个初步了解。
在 Haskell 中,List是一种单类型的数据结构,可以用来存储多个类型相同的元素。我们可以在里面装一组数字或者一组字符,但不能字符和数字装在一起。
note:在ghci下,我们可以使用let关键字来定义一个常量。在ghci下执行let a =1与在脚本中编写a=1是等价的。
ghci> lostNumbers
[ 4 , 8 , 15 , 16 , 23 , 48 ]
如你所见,一个List由方括号括起,其中的元素用逗号分隔开来。若试图写 [1,2,'a',3,'b','c',4]这样的List,Haskell 就会报出这几个字符不是数字的错误。字符串实际上就是一组字符的List,"Hello"只是 ['h','e','l','l','o']的语法糖而已。所以我们可以使用处理List的函数来对字符串进行操作。
将两个List合并是很常见的操作,这可以通过++运算符实现。
ghci> [1 ,2 ,3 ,4 ] ++ [9 ,10 ,11 ,12 ]
[1 ,2 ,3 ,4 ,9 ,10 ,11 ,12 ]
ghci> "hello" ++ " " ++ "world"
"hello world"
ghci> ['w' ,'o' ] ++ ['o' ,'t' ]
"woot"
在使用++运算符处理长字符串时要格外小心(对长List也是同样),
Haskell 会遍历整个的List(++符号左边的那个)。在处理较短的字符串时 问题还不大,但要是在一个5000万长度的List上追加元素,那可得执行好一会儿了。所以说,用:运算符往一个List前端插入元素会是更好的选择。
ghci> 'A' : " SMALL CAT"
"A SMALL CAT"
ghci> 5 :[ 1 , 2 , 3 , 4 , 5 ]
[5 , 1 , 2 , 3 , 4 , 5 ]
:运算符可以连接一个元素到一个List或者字符串之中,而++运算符则是连接两个List。若要使用++运算符连接单个元素到一个List之中,就用方括号把它括起使之成为单个元素的List。
[1,2,3]实际上是1:2:3:[]的语法糖。[]表示一个空List,若要从前端插入3,它就成了[3],再插入2,它就成了[2,3],以此类推。
Note:[],[[]],[[],[],[]]是不同的。第一个是一个空的List,第二个是含有一个空List的List,第三个是含有三个空List的List。
若是要按照索引取得List中的元素,可以使用!!运算符,索引的下标为0。
"A SMALL CAT"
ghci> 5 :[ 1 , 2 , 3 , 4 , 5 ]
[5 , 1 , 2 , 3 , 4 , 5 ]
:运算符可以连接一个元素到一个List或者字符串之中,而++运算符则是连接两个List。若要使用++运算符连接单个元素到一个List之中,就用方括号把它括起使之成为单个元素的List。
[1,2,3]实际上是1:2:3:[]的语法糖。[]表示一个空List,若要从前端插入3,它就成了[3],再插入2,它就成了[2,3],以此类推。
Note:[],[[]],[[],[],[]]是不同的。第一个是一个空的List,第二个是含有一个空List的List,第三个是含有三个空List的List。
若是要按照索引取得List中的元素,可以使用!!运算符,索引的下标为0。
ghci> "Steve Buscemi" !! 6
'B'
ghci> [ 9.4 , 33.2 , 96.2 , 11.2 , 23.25 ] !! 1
33.2
'B'
ghci> [ 9.4 , 33.2 , 96.2 , 11.2 , 23.25 ] !! 1
33.2
但你若是试图在一个只含有4个元素的List中取它的第6个元素,就会报错。要小心!
List同样也可以用来装List,甚至是List的List的List:
ghci> let b = [[ 1 , 2 , 3 , 4 ],[ 5 , 3 , 3 , 3 ],[ 1 , 2 , 2 , 3 , 4 ],[ 1 , 2 , 3 ]]
ghci> b
[[1 , 2 , 3 , 4 ],[ 5 , 3 , 3 , 3 ],[ 1 , 2 , 2 , 3 , 4 ],[ 1 , 2 , 3 ]]
ghci> b ++ [[ 1 , 1 , 1 , 1 ]]
[[1 , 2 , 3 , 4 ],[ 5 , 3 , 3 , 3 ],[ 1 , 2 , 2 , 3 , 4 ],[ 1 , 2 , 3 ],[ 1 , 1 , 1 , 1 ]]
ghci> [ 6 , 6 , 6 ]:b
[[6 , 6 , 6 ],[ 1 , 2 , 3 , 4 ],[ 5 , 3 , 3 , 3 ],[ 1 , 2 , 2 , 3 , 4 ],[ 1 , 2 , 3 ]]
ghci> b !! 2
[1 , 2 , 2 , 3 , 4 ]
ghci> b
[[1 , 2 , 3 , 4 ],[ 5 , 3 , 3 , 3 ],[ 1 , 2 , 2 , 3 , 4 ],[ 1 , 2 , 3 ]]
ghci> b ++ [[ 1 , 1 , 1 , 1 ]]
[[1 , 2 , 3 , 4 ],[ 5 , 3 , 3 , 3 ],[ 1 , 2 , 2 , 3 , 4 ],[ 1 , 2 , 3 ],[ 1 , 1 , 1 , 1 ]]
ghci> [ 6 , 6 , 6 ]:b
[[6 , 6 , 6 ],[ 1 , 2 , 3 , 4 ],[ 5 , 3 , 3 , 3 ],[ 1 , 2 , 2 , 3 , 4 ],[ 1 , 2 , 3 ]]
ghci> b !! 2
[1 , 2 , 2 , 3 , 4 ]
List中的List可以是不同长度,但必须得是相同的类型。如不可以在List中混合放置字符和数组相同,混合放置数值和字符的List也是同样不可以的。
当List内装有可比较的元素时,使用 < , <= , > 和 >=可以比较List的大小。它会先比较第一个元素,若它们的值相等,则比较下一个,以此类推。
ghci> [ 3 , 2 , 1 ] > [ 2 , 1 , 0 ]
True
ghci> [ 3 , 2 , 1 ] > [ 2 , 10 , 100 ]
True
ghci> [ 3 , 4 , 2 ] > [ 3 , 4 ]
True
ghci> [ 3 , 4 , 2 ] > [ 2 , 4 ]
True
ghci> [ 3 , 4 , 2 ] == [ 3 , 4 , 2 ]
True
True
ghci> [ 3 , 2 , 1 ] > [ 2 , 10 , 100 ]
True
ghci> [ 3 , 4 , 2 ] > [ 3 , 4 ]
True
ghci> [ 3 , 4 , 2 ] > [ 2 , 4 ]
True
ghci> [ 3 , 4 , 2 ] == [ 3 , 4 , 2 ]
True
还可以对LIst做啥?如下是几个常用的函数:
head返回一个List的头部,也就是List的首个元素。
ghci> head [ 5 , 4 , 3 , 2 , 1 ]
5
5
tail返回一个LIst的尾部,也就是List除去头部之后的部分。
ghci> tail [ 5 , 4 , 3 , 2 , 1 ]
[4 , 3 , 2 , 1 ]
[4 , 3 , 2 , 1 ]
last返回一个LIst的最后一个元素。
ghci> last [ 5 , 4 , 3 , 2 , 1 ]
1
1
init返回一个LIst出去最后一个元素的部分。
ghci> init [ 5 , 4 , 3 , 2 , 1 ]
ghci> init [ 5 , 4 , 3 , 2 , 1 ]
[5 , 4 , 3 , 2 ]
如果我们把List当做一头怪兽,那这就是它的样子:
![list monster](http://learnyouahaskell.com/listmonster.png)
试一下,若是取一个空List的head又会怎样?
ghci> head []
*** Exception : Prelude .head: empty list
omg,它翻脸了!怪兽压根就不存在,head又从何而来?在使用head,tail,last和init时要小心别用到空的List上,这个错误不会在编译时被捕获。所以说做些工作以防止从空List中取值会是个好的做法。
length返回一个List的长度。
ghci> length [ 5 , 4 , 3 , 2 , 1 ]
5
5
null检查一个List是否为空。如果是,则返回True,否则返回False。应当避免使用xs==[]之类的语句来判断List是否为空,使用null会更好。
ghci> null [ 1 , 2 , 3 ]
False
ghci> null []
True
reverse将一个List反转
ghci> reverse [ 5 , 4 , 3 , 2 , 1 ]
[1 , 2 , 3 , 4 , 5 ]
take返回一个List的前几个元素,看:
[1 , 2 , 3 , 4 , 5 ]
take返回一个List的前几个元素,看:
ghci> take 3 [ 5 , 4 , 3 , 2 , 1 ]
[5 , 4 , 3 ]
ghci> take 1 [ 3 , 9 , 3 ]
[3 ]
ghci> take 5 [ 1 , 2 ]
[1 , 2 ]
ghci> take 0 [ 6 , 6 , 6 ]
[]
[5 , 4 , 3 ]
ghci> take 1 [ 3 , 9 , 3 ]
[3 ]
ghci> take 5 [ 1 , 2 ]
[1 , 2 ]
ghci> take 0 [ 6 , 6 , 6 ]
[]
如上,若是图取超过List长度的元素个数,只能得到原List。若take 0个元素,则会得到一个空List!
drop与take的用法大体相同,它会删除一个List中的前几个元素。
ghci> drop 3 [ 8 , 4 , 2 , 1 , 5 , 6 ]
[1 , 5 , 6 ]
ghci> drop 0 [ 1 , 2 , 3 , 4 ]
[1 , 2 , 3 , 4 ]
ghci> drop 100 [ 1 , 2 , 3 , 4 ]
[]
maximum返回一个List中最大的那个元素。
miniimun返回最小的。
[1 , 5 , 6 ]
ghci> drop 0 [ 1 , 2 , 3 , 4 ]
[1 , 2 , 3 , 4 ]
ghci> drop 100 [ 1 , 2 , 3 , 4 ]
[]
maximum返回一个List中最大的那个元素。
miniimun返回最小的。
ghci> minimum [ 8 , 4 , 2 , 1 , 5 , 6 ]
1
ghci> maximum [ 1 , 9 , 2 , 3 , 4 ]
9
1
ghci> maximum [ 1 , 9 , 2 , 3 , 4 ]
9
sum返回一个List中所有元素的和。
product返回一个List中所有元素的积。
ghci> sum [ 5 , 2 , 1 , 6 , 3 , 2 , 5 , 7 ]
31
ghci> product [ 6 , 2 , 1 , 2 ]
24
ghci> product [ 1 , 2 , 5 , 6 , 7 , 9 , 2 , 0 ]
0
elem判断一个元素是否在包含于一个List,通常以中缀函数的形式调用它。
elem判断一个元素是否在包含于一个List,通常以中缀函数的形式调用它。
ghci> 4 `elem` [ 3 , 4 , 5 , 6 ]
True
ghci> 10 `elem` [ 3 , 4 , 5 , 6 ]
False
True
ghci> 10 `elem` [ 3 , 4 , 5 , 6 ]
False
这就是几个基本的List操作函数,我们会在往后的一节中了解更多的函数。