《Haskell趣学指南》—— 第1章,第1.4节得州区间2

简介: 本节书摘来自异步社区《Haskell趣学指南》一书中的第1章,第1.4节得州区间2,作者 【斯洛文尼亚】Miran Lipovaca,更多章节内容可以访问云栖社区“异步社区”公众号查看 1.4 得州区间2 该怎样得到一个由1~20所有数组成的列表呢?我们完全可以用手把它们全都录入一遍,但显而易见,这并不是完美人士的方案,完美人士都用区间(range)。

本节书摘来自异步社区《Haskell趣学指南》一书中的第1章,第1.4节得州区间2,作者 【斯洛文尼亚】Miran Lipovaca,更多章节内容可以访问云栖社区“异步社区”公众号查看

1.4 得州区间2
该怎样得到一个由1~20所有数组成的列表呢?我们完全可以用手把它们全都录入一遍,但显而易见,这并不是完美人士的方案,完美人士都用区间(range)。区间是构造列表的方法之一,而其中的值必须是可枚举的,或者说,是可以排序的。

例如,数字可以枚举为1、2、3、4等。字符同样也可以枚举:字母表就是A~Z所有字符的枚举。然而人名就不可以枚举了,“John”后面是谁?我不知道。

要得到包含1~20中所有自然数的列表,只要录入[1..20]即可,这与录入[1,2,3,4,5,6,7,8, 9,10,11,12,13,14,15,16,17,18,19,20]完全等价。两者的唯一区别是手写一串非常长的列表比较笨。

下面是一些例子:

ghci> [1..20] 
[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20] 
ghci> ['a'..'z'] 
"abcdefghijklmnopqrstuvwxyz"
ghci> ['K'..'Z'] 
"KLMNOPQRSTUVWXYZ"

区间很聪明,允许你告诉它一个步长。要得到1~20中所有的偶数,或者3的倍数该怎样?只要用逗号将前两个元素隔开,再标上区间的上限就好了:

ghci> [2,4..20] 
[2,4,6,8,10,12,14,16,18,20] 
ghci> [3,6..20] 
[3,6,9,12,15,18] 

尽管区间很聪明,但它恐怕还是难以满足人们对它过分的期许。比如,你就不能通过[1,2,4,8,16..100]这样的语句来获得100以下的所有2的幂。一方面是因为步长只能标明一次,另一方面就是仅凭前几项,数组后面的项也有可能是无法确定的。

注意:
要得到从20到1之间的列表,[20..1]是不可以的,必须得[20,19..1]。对于没有提供步长的区间(如[20..1]),Haskell会先构造一个空的列表,随后从区间的下限开始,不停地赠长,直到大于等于上限为止。既然20已经大于1了,那么所得的结果只能是个空列表。
你也可以不标明区间的上限,从而得到一个无限长度的列表。在后面我们会讲解关于无限列表的更多细节。取前24个13的倍数该怎样?下面是一种方法:

ghci> [13,26..24*13] 
[13,26,39,52,65,78,91,104,117,130,143,156,169,182,195,208,221,234,247,260,273,286,
299,312] 

但有更好的方法——使用无限长度的列表:

ghci> take 24 [13,26..] 
[13,26,39,52,65,78,91,104,117,130,143,156,169,182,195,208,221,234,247,260,273,286,
299,312] 

由于 Haskell 是惰性的,它不会对无限长度的列表直接求值(不然会没完没了)。它会等着,看你会从它那儿取哪些元素。在这里它见你只要前24个元素,便欣然交差。

下面是几个生成无限列表的函数。
cycle函数接受一个列表作为参数并返回一个无限列表。

ghci> take 10 (cycle [1,2,3]) 
[1,2,3,1,2,3,1,2,3,1] 
ghci> take 12 (cycle "LOL ")
"LOL LOL LOL "

repeat函数接受一个值作为参数,并返回一个仅包含该值的无限列表。这与用cycle处理单元素列表的效果差不多。

ghci> take 10 (repeat 5) 
[5,5,5,5,5,5,5,5,5,5] 

若只是想得到包含相同元素的列表,直接使用replicate函数将更加简单,它取一个参数表示列表的长度,一个参数表示列表中要复制的元素:

ghci> replicate 3 10
[10,10,10] 

最后,在区间中使用浮点数要格外小心!浮点数依据定义,只能实现有限的精度。若是在区间中使用浮点数,你就会得到如下的糟糕结果:

ghci> [0.1, 0.3 .. 1] 
[0.1,0.3,0.5,0.7,0.8999999999999999,1.0999999999999999] 
相关文章
|
3月前
|
Java C++ Python
Rust每日一练(Leetday0013) 解数独、外观数列、组合总和
Rust每日一练(Leetday0013) 解数独、外观数列、组合总和
32 0
Rust每日一练(Leetday0013) 解数独、外观数列、组合总和
|
3月前
|
Java Go C++
Golang每日一练(leetDay0115) 重新安排行程、递增的三元子序列
Golang每日一练(leetDay0115) 重新安排行程、递增的三元子序列
33 0
Golang每日一练(leetDay0115) 重新安排行程、递增的三元子序列
|
3月前
|
C++ Rust 算法
Rust每日一练(Leetday0019) 跳跃游戏、合并区间、插入区间
Rust每日一练(Leetday0019) 跳跃游戏、合并区间、插入区间
23 0
Rust每日一练(Leetday0019) 跳跃游戏、合并区间、插入区间
|
3月前
|
Java Go C++
Rust每日一练(leetDay0023) 二进制求和、左右对齐、平方根
Rust每日一练(leetDay0023) 二进制求和、左右对齐、平方根
28 0
Rust每日一练(leetDay0023) 二进制求和、左右对齐、平方根
|
3月前
|
Python Rust Java
Rust每日一练(Leetday0020) 最后单词的长度、螺旋矩阵II、排列序列
Rust每日一练(Leetday0020) 最后单词的长度、螺旋矩阵II、排列序列
64 0
Rust每日一练(Leetday0020) 最后单词的长度、螺旋矩阵II、排列序列
|
3月前
|
Java C++ Python
C/C++每日一练(20230422) 存在重复元素、组合总和、给表达式添加运算符
C/C++每日一练(20230422) 存在重复元素、组合总和、给表达式添加运算符
30 0
C/C++每日一练(20230422) 存在重复元素、组合总和、给表达式添加运算符
|
3月前
|
Java Go Rust
Rust每日一练(Leetday0030) 合并有序数组、格雷编码、子集II
Rust每日一练(Leetday0030) 合并有序数组、格雷编码、子集II
31 0
Rust每日一练(Leetday0030) 合并有序数组、格雷编码、子集II
|
10月前
|
存储 算法 Python
蓝桥杯-区间最大值-python
蓝桥杯-区间最大值-python
104 0
|
11月前
|
Python
Python|Leetcode《334》|递增的三元子序列
Python|Leetcode《334》|递增的三元子序列
|
11月前
|
Rust 算法 Perl
Rust每日一练(Leetday0002) 中位数、回文子串、Z字形变换
Rust每日一练(Leetday0002) 中位数、回文子串、Z字形变换
77 0