Python-IndexError: список индексов выходит за пределы диапазона, пока находится в цикле for - PullRequest
0 голосов
/ 28 сентября 2019

Я новичок в питоне.Я пытаюсь написать код для получения ввода из текстового файла, например

6 6
* o o o o *
o o * o o o
o o * o o *
o o * o o o
o o o o * o
o o o o o o

, подсчета числа "*" рядом с каждой строкой и обновления каждой строки новым счетом, например:

6 6
* 2 1 1 1 *
1 3 * 2 2 2
0 3 * 3 1 *
0 2 * 2 2 2
0 1 1 2 * 1
0 0 0 1 1 1

И обновите это в output.txt.До сих пор мой код принимает входные данные и предоставляет строки, столбцы и матрицы, но как только я попадаю в список для подсчета, он перестает выдавать ошибку

if matrix[num_rows][num_columns][1] == "x": 

IndexError: индекс списка вне диапазона

Мой фрагмент кода:

def parse_in(input_name):
    list_of_lists = []
    with open(input_name,"r") as f:
        for line in f:
            with open(input_name) as f:
                num_rows, num_columns = [int(x) for x in next(f).split()]

                lines = f.read().splitlines()
            # in alternative, if you need to use the file content as numbers
        matrix = []
        print(lines)
        for x in lines:
            matrix.append(x.split(' '))
        print(matrix)
    return matrix, num_rows, num_columns


def detector(matrix, num_rows, num_columns):
    mine_count = 0
    # For every every space around the square, including itself
    for r in range(num_rows):
        for c in range(num_columns):
            # If the square exist on the matrix
            if 0 <= num_rows + r <= 2 and 0 <= num_columns + c <= 2:
                # If the square contains a mine
                if matrix[r][c] == "*":
                    # Raise the mine count
                    mine_count = mine_count + 1
            # If the original square contains a mine
            if matrix[r][c] == "*":
                print(mine_count)
                # Lower the mine count by 1, because the square itself having a mine shouldn't be counted
                mine_count = mine_count - 1
                print(mine_count)
            return mine_count


def parse_out(output_name, my_solution):
    pass


def my_main(input_name, output_name):
    # 1. We do the parseIn from the input file
    lines, num_rows, num_columns = parse_in(input_name)

    # 2. We do the strategy to solve the problem
    my_solution = detector(lines, num_rows, num_columns)

    # 3. We do the parse out to the output file
    parse_out(output_name, my_solution)


if __name__ == '__main__':
    # 1. Name of input and output files
    input_name = "input_2.txt"
    output_name = "output.txt"

    # 2. Main function
    my_main(input_name, output_name)

Ответы [ 2 ]

0 голосов
/ 28 сентября 2019

Сначала прочитайте текстовый файл и получите содержимое строки в массив numpy, с помощью этого:

with open('test1.txt', 'r') as f:
    all_lines = f.readlines()
    mat_shape = tuple(map(int, all_lines[0].split()))
    lines = [i.strip().split() for i in all_lines[1:]]
lines = np.array(lines)

Прочитайте первую строку текстового файла, разбейте, отобразите их в int и сохраните вкортеж, поскольку мы используем его для изменения размера нашей матрицы позже.

lines будет выглядеть так:

[['*' 'o' 'o' 'o' 'o' '*']
 ['o' 'o' '*' 'o' 'o' 'o']
 ['o' 'o' '*' 'o' 'o' '*']
 ['o' 'o' '*' 'o' 'o' 'o']
 ['o' 'o' 'o' 'o' '*' 'o']
 ['o' 'o' 'o' 'o' 'o' 'o']]

Получить соседние элементы для каждой ячейки матрицы, с помощью этой функции:

def get_neighbours(lines, cell):
    row, col = cell
    row_max = len(lines)
    col_max = len(lines[0])
    cell_cont = lines[row][col]
    if cell_cont!="*":
        return [lines[row_d + row][col_d + col] for col_d in [-1,0,1] if (0 <= (col_d + col) < col_max) or (col_d == 0 and row_d==0) for row_d in [-1,0,1] if 0 <= (row_d + row) < row_max ].count('*')
    else:
        return '*'

Функция принимает всю матрицу и определенную ячейку, которая является кортежем номера строки и столбца.Он возвращает только '*', если в ячейке есть звезда, в противном случае целое число - количество звезд в соседних соседних ячейках.

Теперь создайте новый массив и вызовите эту функцию для каждой ячейкиmatrix:

new = []
for i,_ in enumerate(lines):
    for j,_ in enumerate(lines[i]):
        new.append(get_neighbours(lines, (i,j)))
new = np.array(new)

Если вы теперь преобразуете эту матрицу в желаемый формат следующим образом:

new = new.reshape(mat_shape)

Она становится:

[['*' '2' '1' '1' '1' '*']
 ['1' '3' '*' '2' '2' '2']
 ['0' '3' '*' '3' '1' '*']
 ['0' '2' '*' '3' '2' '2']
 ['0' '1' '1' '2' '*' '1']
 ['0' '0' '0' '1' '1' '1']]

Вы можете записать это вновый текстовый файл с таким именем:

with open('new1.txt', 'w') as f:
    f.write(all_lines[0])
    for i in new:
        f.write(' '.join(i))
        f.write('\n')

В файл new1.txt будет записано следующее содержимое:

6 6
* 2 1 1 1 *
1 3 * 2 2 2
0 3 * 3 1 *
0 2 * 2 2 2
0 1 1 2 * 1
0 0 0 1 1 1
0 голосов
/ 28 сентября 2019

При создании матрицы вам не нужны две петли.Вы можете построить матрицу непосредственно в цикле, который читает файл.Вам также не нужно открывать файл несколько раз.

def parse_in(input_name):
    matrix = []
    with open(input_name,"r") as f:
        num_rows, num_columns = [int(x) for x in next(f).split()]
        for line in f:
            matrix.append(line.split(' '))
    return matrix, num_rows, num_columns

Вам не нужно передавать num_rows и num_columns в функцию detector().В отличие от таких языков, как C, Python знает длину списков, поэтому вы можете просто зацикливать элементы списка напрямую.И вы можете использовать enumerate() для получения индексов во время зацикливания.

При подсчете количества мин рядом с квадратом, вам просто нужно выполнить цикл от r-1 до r+1 и от c-1 до c+1.И вам нужно установить mine_count в 0 перед этим циклом.

def detector(matrix):
    result = []
    for r, row in enumerate(matrix):
        result_row = []
        for c, cell in enumerate(row):
            if cell == "*":
                result_row.append(cell)
            else:
                mine_count = 0
                for x in range(c-1, c+2):
                    for y in range(r-1, r+2):
                        if 0 <= x < len(row) and 0 <= y < len(matrix) and matrix[x][y] == "*":
                            mine_count += 1
                result_row.append(str(mine_count))
        result.append(result_row)
    return result
...