二维数组就是一张表格:第一个下标选行,第二个下标选列。 字符串是字符排成一排,所以数组那一套下标、长度全都能用。 但字符数不等于字节数:中文一个字在 UTF-8 里占 3 个字节,按字节截断会切出乱码。
2.4 讲了一排盒子,2.5 讲了什么时候该开一排。这一篇把盒子摞成楼。
教材用的比方是旅馆:grid[1] 是一层楼,grid[1][2] 是那一层的第三个房间。
字符串放在这一节讲,是因为它本质上就是「一排字符」——理解了数组,字符串的下标、切片、
长度全是白送的。
一、二维数组就是一张表格
三个人、四门课的成绩,摆成表格是三行四列。用一维数组只能存一行,要存整张表就得把数组摞起来。
grid = [[80, 90, 70, 85], [60, 75, 88, 92], [95, 65, 72, 58]]——外层三个元素,
每个元素本身又是一个四个数的数组。
所以二维数组不是一种新东西,它是「元素还是数组」的数组。这个说法很重要,三维、
四维都是这么套下去的。
旅馆的比方就是从这里来的:先找到楼层,再找到房间。两层门牌,缺一层都进不去。
二、两个下标各管一件事
grid[1] 给出 [60, 75, 88, 92],是李四的四门课,一整个数组。
grid[1][2] 给出 88,是李四的第三门课。先取行,再取列。
演示里那句提醒别忽略:grid[1][2] 和 grid[2][1] 是两个完全不同的格子。
前者是李四的第 3 门,后者是王五的第 2 门。
一维数组写错下标只是越界,报错还算痛快; 二维数组把两个下标写反,往往不报错,只是取到了别人的数。这种错要查很久。 所以约定一个顺序并且一直用:先行后列,和数学里的矩阵一致。
三、字符串就是字符排成一排
s = '算法入门',可以取 s[0] 得「算」,s[1] 得「法」,s[2:4] 得「入门」。
下标能用、切片能用、
len() 能用——凡是数组能做的,字符串基本都能做。因为它本来就是「一排字符」。
区别在于字符串不能再改。s[0] = '算' 这种写法在 Python 里直接报错,要改只能拼一个新的。
这一点教材没强调,但写代码时天天撞。
演示里 len(s) 得 4,s[2:4] 得两个字符——长度和切片都以「字符」为单位,不是以字节为单位。
四、字符数不等于字节数
同样这四个字,存成 UTF-8 要 12 个字节。中文一个字占 3 个字节,len() 数的是字,不是字节。
所以「字符串长度是 4」和「占 12 个字节」两句都对,它们回答的是不同的问题。
这条区别在截断时会咬人:按字节切到第 6 个字节,正好把一个汉字切成两半,结果就是乱码。
演示里那句提醒说的就是这个。
要按字节处理就用 s.encode('utf-8'),那时 len() 才是 12。
先想清楚你要的是字符还是字节,再选哪一个。
五、求长度的两个办法
教材列了两种:直接问长度,或者一个字符一个字符数到结尾为止。
| 办法 | 怎么做 | 什么时候用 |
|---|---|---|
| 直接问长度 | len(s) 一次拿到 |
有现成函数,几乎总用它 |
| 数到结尾为止 | 一个字符一个字符往后走,走到头 | 没有长度函数的语言,或边读边处理 |
演示里第一种一步得 4,第二种数了 4 次才到头。结果一样,代价不同。
第二种在 C 里叫「找结尾的那个 0」:C 的字符串不在开头存长度,只保证最后有个