使用for循环过滤棋盘列表时意外跳过元素的问题
国际象棋棋盘过滤棋子位置时循环跳过元素的问题
我在开发国际象棋棋盘指定位置的所有可能走法功能,尝试过滤掉已有棋子的位置,生成仅包含空位的二维数组。但过滤数组每行时,循环意外跳过了每隔一个的元素。
原代码
files = ['A','B','C','D','E','F','G','H'] ranks_n = [1,2,3,4,5,6,7,8] ranks = ['1','2','3','4','5','6','7','8'] board = [ ['A8','B8','C8','D8','E8','F8','G8','H8'], ['A7','B7','C7','D7','E7','F7','G7','H7'], ['A6','B6','C6','D6','E6','F6','G6','H6'], ['A5','B5','C5','D5','E5','F5','G5','H5'], ['A4','B4','C4','D4','E4','F4','G4','H4'], ['A3','B3','C3','D3','E3','F3','G3','H3'], ['A2','B2','C2','D2','E2','F2','G2','H2'], ['A1','B1','C1','D1','E1','F1','G1','H1'], ] board_n = [ [18,28,38,48,58,68,78,88], [17,27,37,47,57,67,77,87], [16,26,36,46,56,66,76,86], [15,25,35,45,55,65,75,85], [14,24,34,44,54,64,74,84], [13,23,33,43,53,63,73,83], [12,22,32,42,52,62,72,82], [11,21,31,41,51,61,71,81] ] white = { 'p1': 'A2', 'p2': 'B2', 'p3': 'C2', 'p4': 'D2', 'p5': 'E2', 'p6': 'F2', 'p7': 'G2', 'p8': 'H2', 'R1': 'A1', 'N1': 'B1', 'B1': 'C1', 'Q': 'D1', 'K': 'E1', 'B2': 'F1', 'N2': 'G1', 'R2': 'H1', } black = { 'p1': 'A7', 'p2': 'B7', 'p3': 'C7', 'p4': 'D7', 'p5': 'E7', 'p6': 'F7', 'p7': 'G7', 'p8': 'H7', 'R1': 'A8', 'N1': 'B8', 'B1': 'C8', 'Q': 'D8', 'K': 'E8', 'B2': 'F8', 'N2': 'G8', 'R2': 'H8', } b_keys=list(black.keys()) b_values=list(black.values()) w_keys=list(white.keys()) w_values=list(white.values()) pos_board = [] board_file = [] for b in board: board_file = b for n in b: if n in w_values or n in b_values: print(n) board_file.remove(n) pos_board.append(board_file) for p in pos_board: print(p)
原输出
C8 E8 G8 A7 C7 E7 G7 A2 C2 E2 G2 A1 C1 E1 G1 ['B8', 'D8', 'F8', 'H8'] ['B7', 'D7', 'F7', 'H7'] ['A6', 'B6', 'C6', 'D6', 'E6', 'F6', 'G6', 'H6'] ['A5', 'B5', 'C5', 'D5', 'E5', 'F5', 'G5', 'H5'] ['A4', 'B4', 'C4', 'D4', 'E4', 'F4', 'G4', 'H4'] ['A3', 'B3', 'C3', 'D3', 'E3', 'F3', 'G3', 'H3'] ['B2', 'D2', 'F2', 'H2'] ['B1', 'D1', 'F1', 'H1']
预期结果
第1、2、7、8行应完全为空(这些位置均有棋子),但实际输出中这些行仍保留了B、D、F、H列的位置。
问题原因
你在遍历列表b的同时调用board_file.remove(n),这会直接修改正在遍历的列表,导致索引错乱。比如原行是['A8','B8','C8','D8',...],当移除A8后,列表变为['B8','C8','D8',...],下一次循环会取索引1的元素(也就是原来的C8),直接跳过了B8,最终导致每隔一个元素被遗漏。
修复方案
不要在遍历原列表时修改它,而是创建新列表存储空位;同时用集合存储已占用位置,提升查询效率:
files = ['A','B','C','D','E','F','G','H'] ranks_n = [1,2,3,4,5,6,7,8] ranks = ['1','2','3','4','5','6','7','8'] board = [ ['A8','B8','C8','D8','E8','F8','G8','H8'], ['A7','B7','C7','D7','E7','F7','G7','H7'], ['A6','B6','C6','D6','E6','F6','G6','H6'], ['A5','B5','C5','D5','E5','F5','G5','H5'], ['A4','B4','C4','D4','E4','F4','G4','H4'], ['A3','B3','C3','D3','E3','F3','G3','H3'], ['A2','B2','C2','D2','E2','F2','G2','H2'], ['A1','B1','C1','D1','E1','F1','G1','H1'], ] white = { 'p1': 'A2', 'p2': 'B2', 'p3': 'C2', 'p4': 'D2', 'p5': 'E2', 'p6': 'F2', 'p7': 'G2', 'p8': 'H2', 'R1': 'A1', 'N1': 'B1', 'B1': 'C1', 'Q': 'D1', 'K': 'E1', 'B2': 'F1', 'N2': 'G1', 'R2': 'H1', } black = { 'p1': 'A7', 'p2': 'B7', 'p3': 'C7', 'p4': 'D7', 'p5': 'E7', 'p6': 'F7', 'p7': 'G7', 'p8': 'H7', 'R1': 'A8', 'N1': 'B8', 'B1': 'C8', 'Q': 'D8', 'K': 'E8', 'B2': 'F8', 'N2': 'G8', 'R2': 'H8', } # 合并黑白棋子的位置,用集合存储提升查询速度 occupied = set(white.values()).union(set(black.values())) pos_board = [] for row in board: # 筛选出未被占用的位置,生成新行 empty_row = [pos for pos in row if pos not in occupied] pos_board.append(empty_row) for p in pos_board: print(p)
修复后输出
[] [] ['A6', 'B6', 'C6', 'D6', 'E6', 'F6', 'G6', 'H6'] ['A5', 'B5', 'C5', 'D5', 'E5', 'F5', 'G5', 'H5'] ['A4', 'B4', 'C4', 'D4', 'E4', 'F4', 'G4', 'H4'] ['A3', 'B3', 'C3', 'D3', 'E3', 'F3', 'G3', 'H3'] [] []
优化说明
- 使用集合存储已占用位置:集合的成员查询是O(1)时间复杂度,比列表的O(n)更高效
- 列表推导式生成新行:避免了遍历原列表时修改它的问题,代码更简洁易读
内容的提问来源于stack exchange,提问作者Drew Olson
相关产品推荐
相关产品推荐

