程序员入伙书——数组
- 2013年01月6日
- 发布在 infotech . on my mind
- 留下评论
从前我用过的程序示例里面,使用的数据都是分离的、独立的。就是说,每个常量和变量,各有各的用途,没有“我们是一伙的”这样的共性。而在现实世界里,成群结队地出现的数据是大多数。例如一架飞机上的旅客,一个班级的学生,奥运会的参赛国。
我见过的所有编程语言都有数组(Array,List)的概念,用来存储具有共同属性的批量数据。在Python里,数组用一对中括号包围的一群数据来表示,数据之间用逗号隔开。例如:
>>> countries = ['China', 'USA', 'Germany', 'Canada', 'Japan'] >>> countries[0] 'China' >>> countries[3] 'Canada' >>> countries[4] 'Japan' >>>
在这里,countries就是一个数组,它有五个元素(Element),每个元素都是一个字符串表示的国名。引用这些元素的时候,我们使用一个整数,来指明它在数组里的位置,这个整数叫做下标(Index)。和大家的习惯稍有差异的是,在Python里,当我们说“数组的第一个元素”时,我们用的下标是0,第二个元素的下标是1,第三个元素的下标是2,依此类推。所以上面的程序范例里面,countries[0]打印出来的是第一个国名China,第五个国名使用的下标是4。
如果你觉得这个规则挺怪异的,想一想这个问题:进入一座楼房,爬到一楼需要爬几层楼梯?爬到五楼需要爬几层楼梯?然后你就释然了,因为对于计算机来说,数组就像楼层,一楼就是它的第一个元素,其它的楼层都是相对于一楼的偏移量。英式英语里,一楼叫做Ground Floor,二楼叫做First Floor,三楼叫做Second Floor,这就是计算机式的思维。
C/C++、Python、Perl、Java、PHP等语言里,第一个元素都是用下标0来表示。FORTRAN、BASIC、PASCAL等语言里,第一个元素是用下标1来表示。这两种表示方法都是合理的,照顾不同人群的思维习惯。
在刚才这个数组里,使用countries[5]会看到什么?
>>> countries[5] Traceback (most recent call last): File "<pyshell#19>", line 1, in countries[5] IndexError: list index out of range >>>
Python抱怨道:越界(out of range)了。越界是不熟练的程序员常犯的错误之一,通常引起程序的崩溃。如果是操作系统级别的程序——例如Windows——你可能会看到蓝屏。
如果你想再添加一个国家名字到countires里,不能写countires[5] = ‘Turkey’——因为这样会引起越界——而是写:
>>> countries.append('Turkey') >>> countries ['China', 'USA', 'Germany', 'Canada', 'Japan', 'Turkey'] >>>
来,我们看看用这个数组可以干什么:
>>> len(countries) # 看看有几个国家参赛 6 >>> countries.sort() # 排一下奥运会入场顺序 >>> countries ['Canada', 'China', 'Germany', 'Japan', 'Turkey', 'USA'] >>> countries.index('China') # 中国排第几个出场?注意返回的结果要加1 1 >>> 'USA' in countries # 美国有没有参赛? True >>> countries.extend(['France', 'Russia']) # 法国和俄罗斯也要参赛 >>> countries ['Canada', 'China', 'Germany', 'Japan', 'Turkey', 'USA', 'France', 'Russia'] >>>
对数组的操作还有许多,我们将来会陆续用到。眼前不需要记得十分仔细,用到的时候自然就明白了。
数组可以成为更大的数组里的元素,当这种情况出现时,更大的数组就成了多维数组(Multi-Dimension List)。例如一个学校有三个年级,每个年级有六个班,每个班有若干学生。这就是一个三维数组(3-Dimension List)。
>>> school = [ # 三个年级 \ [ # 一年级的六个班 \ ['Mike', 'Tom', 'Tony'], ['Alice', 'Peter', 'Mike'], \ ['David', 'Mark', 'Shirley'], ['Andy', 'Sean', 'Connie'], \ ['Steve', 'Tony', 'Ryan'], ['Gloria', 'Tracy', 'Jane'] \ ], \ [ # 二年级的六个班 \ ['Mike', 'Tom', 'Tony'], ['Alice', 'Peter', 'Mike'], \ ['Lynsey', 'Mark', 'Shirley'], ['Andy', 'Sean', 'Connie'], \ ['Steve', 'Tony', 'Ryan'], ['Gary', 'Tracy', 'Jane'] \ ], \ [ # 三年级的六个班 \ ['Mike', 'Tom', 'Tony'], ['Alice', 'Peter', 'Mike'], \ ['David', 'Roy', 'Shirley'], ['Andy', 'Sean', 'Connie'], \ ['Steve', 'Tony', 'Ryan'], ['Ray', 'Tracy', 'Justin'] \ ] \ ] >>> school[0][3][2] # 一年级四班的第三位同学的名字? 'Connie' >>> school[1][5] # 二年级六班的所有学生? ['Gary', 'Tracy', 'Jane'] >>>
用二维数组玩一下。在数学里有个东东叫“幻方”,在一个方格阵列里填一连串的整数,每行每列及对角线的和都相等。这个奇妙的东西,是有算法的,奇数级幻方的算法尤为简单:
- 画一个NxN的方格阵列。
- 在最右边、正中间的格子里填1。
- 笔向右下方移动,如果移出右边界,则跳到左边第一列,如果移出下边界,则跳到顶端第一行。填下一个数字。
- 每填到N的倍数之后,笔向左边的格子移一格。填下一个数字。
- 回到第3步,直到填满整个方格阵列为止。
# 获得一个奇数 N = 0 while N <= 0 or N % 2 == 0: string = input("Please input an odd integer: ") if string.isdigit(): N = int(string) # 初始化一个NxN的二维数组,每个格子里暂且填上0 a = [[0] * N] * N # 下标设置为最右侧正中间一行 i = N // 2 j = N - 1 # 从1到N*N填写: for n in range(1, N * N + 1): a[i][j] = n if (n % N): i += 1 # 向下方移动 j += 1 # 向右侧移动 if i >= N: # 如果移出下边界,则回到顶行 i = 0 if j >= N: # 如果移出右边界,则回到左列 j = 0 else: # 每当数字可以被N整除时,向左移一格 j -= 1 # 打印幻方数组 strfmt = "%%%dd" % (len(str(N * N)) + 1) for i in range(N): for j in range(N): print(strfmt % a[i][j], end = '') print()
执行一下看看,第一次我们输入3,得到的是中国古代著名的九宫格,每行每列对角线相加都等于15。第二次我们玩个大的,输入7,每行每列对角线相加都等于175。你来试试?输入多大的奇数都可以。
>>> ======================== RESTART ======================== >>> Please input an odd integer: 3 4 3 8 9 5 1 2 7 6 >>> ======================== RESTART ======================== >>> Please input an odd integer: 7 22 21 13 5 46 38 30 31 23 15 14 6 47 39 40 32 24 16 8 7 48 49 41 33 25 17 9 1 2 43 42 34 26 18 10 11 3 44 36 35 27 19 20 12 4 45 37 29 28 >>>