zoukankan      html  css  js  c++  java
  • 大爽Python入门教程 64 容器进阶 嵌套 二维列表

    大爽Python入门公开课教案 点击查看教程总目录

    1 双层循环

    双层循环,或者说嵌套循环,
    在一个循环里套一个循环。

    介绍嵌套容器之前,先介绍下嵌套循环。

    这有什么用呢。

    举一个例子,如何输出9x9乘法表。

    1x1= 1  
    1x2= 2  2x2= 4  
    1x3= 3  2x3= 6  3x3= 9  
    1x4= 4  2x4= 8  3x4=12  4x4=16  
    1x5= 5  2x5=10  3x5=15  4x5=20  5x5=25  
    1x6= 6  2x6=12  3x6=18  4x6=24  5x6=30  6x6=36  
    1x7= 7  2x7=14  3x7=21  4x7=28  5x7=35  6x7=42  7x7=49  
    1x8= 8  2x8=16  3x8=24  4x8=32  5x8=40  6x8=48  7x8=56  8x8=64  
    1x9= 9  2x9=18  3x9=27  4x9=36  5x9=45  6x9=54  7x9=63  8x9=72  9x9=81
    

    其实现代码如下

    for i in range(1, 10):
        for j in range(1, 10):
            if j <= i:
                print("{}x{}={:>2} ".format(j, i, i*j), end=" ")
    
        print()
    

    此时再来分析下代码,
    两层循环中的i和j分别代表了什么。

    i代表的是其中蓝色的1-9
    j代表的是绿色的1-9

    两层循环:
    第二层循环,用于输出一行上的具体的列,
    即第二层循环执行完,就输出了一行。

    第一层循环,用于输出多行,
    具体是让第二层循环多次执行,从而输出多行。

    理解i和j,最好从行与列的角度去理解。

    2 认识嵌套列表

    初步介绍

    列表里面嵌套列表,也常称为二维列表。
    举个例子,这是个3x3(3行3列)的二位列表。

    [
        [0, 0, 0],
        [0, 0, 0],
        [0, 0, 0],
    ]
    

    那么这样的列表有什么意义呢,
    二维列表,常常用于去表示二维的格子游戏。
    比如上面的3x3就可以用来表示井字棋。

    实例一 井字棋

    比如下面的井字棋。

    怎么用二维列表表示呢
    这个时候其实有比较大的灵活度。
    就是哪种棋子用哪个符号表示是我们可以选择的,
    当然,不同的表示方式,
    可能会让相关问题解决方式的难度也变得不同。

    这里介绍两种表示方式(并不唯一,可以自由定义)。

    1. 用数字
      没有棋子的格子用0表示
      X棋子的格子用1表示
      O棋子的格子用2表示
      那么上面的井字棋用列表表示如下
    board = [
        [1, 1, 1],
        [2, 1, 0],
        [2, 0, 2],
    ]
    
    1. 用字母
      没有棋子的格子用空格" "表示
      X棋子的格子用"X"表示
      O棋子的格子用"O"表示
      那么上面的井字棋用列表表示如下
    board = [
        ["X", "X", "X"],
        ["O", "X", " "],
        ["O", " ", "O"],
    ]
    

    实例二 俄罗斯方块

    之前做过一个俄罗斯方块的教程
    但那整个教程对现阶段来讲,比较复杂。
    这里只取其中的二维列表过来认识与分析。

    这是一个该游戏中间过程截图(没有实现检查与清理功能)

    这个时候游戏面板中的方格面板对应的二维列表情况如下。

    board = [
        ['', '', '', '', '', '', '', '', '', '', '', ''],
        ['', '', '', '', '', '', '', '', '', '', '', ''],
        ['', '', '', '', '', '', '', '', '', '', '', ''],
        ['', '', '', '', '', '', '', '', '', '', '', ''],
        ['', '', '', '', '', '', '', '', '', '', '', ''],
        ['', '', '', '', '', '', '', '', '', '', '', ''],
        ['', '', '', '', '', '', '', '', '', '', '', ''],
        ['', '', '', '', '', '', '', '', '', '', '', ''],
        ['', '', '', '', '', '', '', '', '', '', '', ''],
        ['', '', '', '', '', '', '', '', '', '', '', ''],
        ['', '', '', '', '', '', '', '', '', '', '', ''],
        ['', '', '', '', '', '', '', '', '', '', '', ''],
        ['', '', '', '', '', '', '', '', '', '', '', ''],
        ['', '', '', '', '', '', '', 'L', '', '', '', ''],
        ['', '', '', '', '', 'L', 'L', 'L', '', '', '', ''],
        ['', '', 'I', '', 'Z', 'Z', 'Z', 'Z', '', '', '', 'Z'],
        ['', 'T', 'I', 'I', 'S', 'Z', 'Z', 'Z', 'Z', '', 'Z', 'Z'],
        ['T', 'T', 'I', 'I', 'S', 'S', 'S', 'T', 'T', 'T', 'Z', 'L'],
        ['J', 'T', 'I', 'I', 'J', 'S', 'S', 'S', 'T', 'L', 'L', 'L'],
        ['J', 'J', 'J', 'I', 'J', 'J', 'J', 'S', 'I', 'I', 'I', 'I']
    ]
    

    这是一个20x12 (20行12列) 的二维列表。

    其中''空字符串对应空白格子。
    'O', 'S', 'T', 'I', 'L', 'J', 'Z'等字母对应不同种类的俄罗斯方块,
    有不同的颜色。

    3 快速新建二维列表

    使用列表生成式

    创建3行4列的空字符串组成的二位列表。

    board = [
        ["" for ci in range(4)] for ri in range(3)
    ]
    

    board如下

    [
        ['', '', '', ''],
        ['', '', '', ''],
        ['', '', '', '']
    ]
    

    使用二层循环

    创建3行4列的空字符串组成的二位列表。

    board = []
    for ri in range(3):
        row = []
        for ci in range(4):
            row.append("")
        board.append(row)
    

    board如下

    [
        ['', '', '', ''],
        ['', '', '', ''],
        ['', '', '', '']
    ]
    

    4 嵌套列表初步使用

    本小部分用到的二维列表如下

    board_1 = [
        ['1', '2', '3', '4'],
        ['A', 'B', 'C', 'D'],
        ['+', '-', '*', '/']
    ]
    

    0. 得到二维列表的行列总数(总行数,总列数)。

    r = len(board_1)
    c = len(board_1[0])
    

    1. 根据行序号,列序号得到对应的值

    得到C

    ri, ci = 1, 2
    cell = board_1[ri][ci]
    

    2. 找到某个值对应的行列序号, 比如找到-

    find_r, find_c = -1, -1  # 默认值,用于处理没找到的情况
    
    r = len(board_1)
    c = len(board_1[0])
    for ri in range(r):
        for ci in range(c):
            if board[ri][ci] == "-":
                find_r, find_c = ri, ci
                break
    

    3. 得到某一行、某一列

    得到某一行的所有格子,代码比较容易,如下(比如第一行)

    row1 = board[1]  # 结果为:['A', 'B', 'C', 'D']
    

    得到一列相对麻烦一点,如下(得到第一列)

    column1 = [board[ri][1] for ri in range(r)]  # 结果为:['2', 'B', '-']
    

    5 使用嵌套使用实例

    井字棋检测

    以上面举得例子为例

    board = [
        ["X", "X", "X"],
        ["O", "X", " "],
        ["O", " ", "O"],
    ]
    

    这个我们能看出来,是"X"对应得玩家赢了。
    那么能不能实现一个程序,来判断是哪个玩家赢了呢?

    具体一点,实现一个函数get_ttt_winner(board)
    接受一个3x3的二维列表board作为参数,
    返回胜利玩家的棋子符号:"X", "O", " "(没有人赢)。
    补充: ttt是因为井字棋对应的英文是Tic-Tac-Toe。。。

    思路分析:
    这个时候,需要检查的是所有行,所有列,以及两个对角线。
    这些本质上,都是三个格子组成的一串。

    那么这里设计出一个对应的子函数check_bunch_match(bunch, symbol)
    能够检查三个格子组成的一串bunch是否是某个玩家的棋子symbol
    这样的解决总问题中的子问题的函数,常称为辅助函数help function

    def check_bunch_match(bunch, symbol):
        res = True
        for one in bunch:
            if one != symbol:
                res = False
                break
    
        return res
    

    然后主函数就好写些了。
    get_ttt_winner(board)
    实现代码如下

    def get_ttt_winner(board):
        r, c = len(board), len(board[0])
        for symbol in "XO":
            for ri in range(r):
                row = board[ri]
                if check_bunch_match(row, symbol):
                    return symbol
    
            for ci in range(c):
                column = [board[ri][ci] for ri in range(r)]
                if check_bunch_match(column, symbol):
                    return symbol
    
            diagonal_1 = [board[ri][ri] for ri in range(r)]
            diagonal_2 = [board[ri][c-ri-1] for ri in range(r)]
            if check_bunch_match(diagonal_1, symbol):
                return symbol
            if check_bunch_match(diagonal_2, symbol):
                return symbol
    
        return "N"
    

    调用语句如下

    board = [
        ["X", "X", "X"],
        ["O", "X", " "],
        ["O", " ", "O"],
    ]
    
    r = get_ttt_winner(board)
    print(r)
    

    输出如下

    X
    

    俄罗斯方块检测

    上面给的俄罗斯方块例子中,没有实现检查与清理功能。
    那么我们接下来实现这个功能。

    具体一点,实现一个函数check_and_clear(board)
    接受一个二维列表board作为参数(board的行列数不确定,但都大于0),
    检测是否有行上占满了俄罗斯方格,有则清理,
    直接在board上操作,不用返回。

    为了方便看到效果,函数中,清理完毕后,直接以可读性比较高的格式来展示board
    空格子展示为_, 有俄罗斯方块的格子,用方块对应的字符展示。

    思路分析:
    需要一个子函数check_row_complete(row),检查一行row是否填满。

    def check_row_complete(row):
        for cell in row:
            if cell=='':
                return False
    
        return True
    

    然后主函数check_and_clear(board)如下

    def check_and_clear(board):
        has_complete_row = False
        r, c = len(board), len(board[0])
        for ri in range(r):
            if check_row_complete(board[ri]):
                # 当前行可消除
                if ri > 0:
                    for cur_ri in range(ri, 0, -1):
                        board[cur_ri] = board[cur_ri-1][:]
                    board[0] = ['' for j in range(c)]
                else:
                    board[ri] = ['' for j in range(c)]
    
        # display
        for row in board:
            for cell in row:
                if cell:
                    print(cell, end="")
                else:
                    print("_", end="")
    
            print()
    

    调用代码如下

    board = [
        ['', '', '', '', '', '', '', '', '', '', '', ''],
        ['', '', '', '', '', '', '', '', '', '', '', ''],
        ['', '', '', '', '', '', '', '', '', '', '', ''],
        ['', '', '', '', '', '', '', '', '', '', '', ''],
        ['', '', '', '', '', '', '', '', '', '', '', ''],
        ['', '', '', '', '', '', '', '', '', '', '', ''],
        ['', '', '', '', '', '', '', '', '', '', '', ''],
        ['', '', '', '', '', '', '', '', '', '', '', ''],
        ['', '', '', '', '', '', '', '', '', '', '', ''],
        ['', '', '', '', '', '', '', '', '', '', '', ''],
        ['', '', '', '', '', '', '', '', '', '', '', ''],
        ['', '', '', '', '', '', '', '', '', '', '', ''],
        ['', '', '', '', '', '', '', '', '', '', '', ''],
        ['', '', '', '', '', '', '', 'L', '', '', '', ''],
        ['', '', '', '', '', 'L', 'L', 'L', '', '', '', ''],
        ['', '', 'I', '', 'Z', 'Z', 'Z', 'Z', '', '', '', 'Z'],
        ['', 'T', 'I', 'I', 'S', 'Z', 'Z', 'Z', 'Z', '', 'Z', 'Z'],
        ['T', 'T', 'I', 'I', 'S', 'S', 'S', 'T', 'T', 'T', 'Z', 'L'],
        ['J', 'T', 'I', 'I', 'J', 'S', 'S', 'S', 'T', 'L', 'L', 'L'],
        ['J', 'J', 'J', 'I', 'J', 'J', 'J', 'S', 'I', 'I', 'I', 'I']
    ]
    
    check_and_clear(board)
    

    输出如下

    ____________
    ____________
    ____________
    ____________
    ____________
    ____________
    ____________
    ____________
    ____________
    ____________
    ____________
    ____________
    ____________
    ____________
    ____________
    ____________
    _______L____
    _____LLL____
    __I_ZZZZ___Z
    _TIISZZZZ_ZZ
    

    6 简单回顾

    二维列表常用语法

    获取总行数和总列数。

    r = len(board)
    c = len(board[0])
    

    得到第ri行,第ci的内容: board[ri][ci]

  • 相关阅读:
    LeetCode 75. Sort Colors(按颜色进行排序)
    LeetCode 451. Sort Characters By Frequency(按照字符出现次数对字符串排序)
    LeetCode 347. Top K Frequent Elements(出现频率最多的 k 个元素)
    LeetCode 215. Kth Largest Element in an Array(数组求第k大)
    CF #629 Div.3 E(LCA)F
    系统函数
    CASE表达式
    循环得出数据库中所有的 DB_ID,DB_NAME
    数据库的编码问题
    检验临时表是否存在
  • 原文地址:https://www.cnblogs.com/BigShuang/p/15630242.html
Copyright © 2011-2022 走看看