Перебор списка внутри списка в python

#python #python-3.x

#python #python-3.x

Вопрос:

У меня возникла проблема, когда мне приходится перебирать список размером 5×5 в списке. Итак, я создал список внутри списка, в котором все элементы равны 0 для удобства:

 lst = [[0 for x in range(6)] for y in range(6)]
print(lst)
  

что даст мне:

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

Я должен иметь возможность начинать с любой координаты в этом вложенном списке, например, lst[3] [2], затем продолжайте проверять каждую координату lst [3] [3], lst [3] [4], lst [3] [4], lst [4][0], … и так далее, пока я не достигну максимума, который равен st [4] [4], после чего мне нужно вернуться к lst [4] [3], lst [4] [2], lst [4] [1], … пока он не достигнет lst [0] [0] после чего я должен выполнить повторный цикл. Это похоже на бесконечный цикл, в котором я начинаю с определенного места, а затем бесконечно перебираю туда и обратно, пока не скажу ему остановиться.

Я могу выполнить вложенный цикл, но он останавливается на lst[4],[4]:

 for x in range(len(lst)):
    for y in range(len(lst)):
        lst[x][y] = do something
  

Я могу настроить диапазоны, чтобы они начинались с определенной координаты, но я не могу создать бесконечный цикл, который будет продолжать цикл взад и вперед. Я также попытался добавить цикл while:

 while True:
    for x in range(len(lst)):
        for y in range(len(lst)):
            lst[x][y] = do something
  

но после того, как он полностью зацикливается, он начинается сначала с lst[0][0], а не с lst [4][3] . Не говоря уже о том, что он начинается с начальной точки, которую я выбрал.

Комментарии:

1. Во-первых, максимальное значение равно [5][5], а не [4][4]. Во-вторых, вы хотите изменить направление в конце, а не цикл. Правильно ли это?

2. Да, я хотел бы изменить направление в конце. Прошу прощения за [4] [4] Я неправильно создал цикл внутри цикла

Ответ №1:

С местоположением легче работать, если вы рассматриваете местоположение в массиве как линейное местоположение и вычисляете x, y:

 import random

MAX_X,MAX_Y = 3,3
L = [[0] * MAX_Y for _ in range(MAX_X)]

# Initial array values
cnt = 1
for x in range(MAX_X):
    for y in range(MAX_Y):
        L[x][y] = cnt
        cnt  = 1

print(L)

# Pick a linear starting location
cur = random.randrange(MAX_X * MAX_Y)
d = 1 # direction to advance
while True:
    x,y = divmod(cur,MAX_Y) # compute x,y from linear location
    print(f'{x},{y} = {L[x][y]}')
    cur  = d  # advance in direction

    # if went off either end, reverse direction
    if cur == MAX_X * MAX_Y or cur == -1: 
        d = -d
        cur  = 2 * d # stepped one off the wrong way, so go back two.
  
 [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
2,0 = 7
2,1 = 8
2,2 = 9
2,1 = 8
2,0 = 7
1,2 = 6
1,1 = 5
1,0 = 4
0,2 = 3
0,1 = 2
0,0 = 1
0,1 = 2
0,2 = 3
1,0 = 4
1,1 = 5
1,2 = 6
2,0 = 7
2,1 = 8
2,2 = 9
2,1 = 8
2,0 = 7
  ...
  

Другой вариант, если 2D-матрица не является жестким требованием, а массив доступен только для чтения, — это развернуть цикл. Создайте единый массив со значениями из 2D-массива в порядке возрастания, затем в порядке убывания. Если вы хотите начать с определенного местоположения в массиве, вычислите начальное местоположение и срежьте предыдущие значения до конца массива:

 import random
import itertools

MAX_X,MAX_Y = 3,3
L = [[0] * MAX_Y for _ in range(MAX_X)]

# Initial array values (same as before)
cnt = 1
for x in range(MAX_X):
    for y in range(MAX_Y):
        L[x][y] = cnt
        cnt  = 1

print(L)

linear = sum(L,[]) # Make a 1D array joining all the rows.

# Pick a starting X/Y location
start_x = random.randrange(MAX_X)
start_y = random.randrange(MAX_Y)

# compute its linear location
cur = start_x * MAX_Y   start_y

# slice elements before starting location to end of the list
# and include the reversed array values as well.
unrolled = linear[cur:]   linear[-2:0:-1]   linear[:cur]
print(unrolled)

# cycle through the list endlessly
for n in itertools.cycle(unrolled):
    print(n)
  
 [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
[5, 6, 7, 8, 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, 3, 4]
5
6
7
8
9
8
7
6
5
4
3
2
1
2
3
4
5
6
...
  

Ответ №2:

Похоже, это работает:

 import time

def showgrid(lst):
   for i in lst:
      for j in i:
         print(str(j).center(3),end=' ')
      print()
   print()


lst = [[0 for x in range(3)] for y in range(3)]  # array all zeros

d = 1 # direction, start forward

x,y = 1,1 # start mid grid

ctr = 1  # data for array position
while True:
   lst[y][x] = ctr # set array data
   x =d  # next cell
   if x == len(lst[0]) or x == -1: # reached end of row
      y =d   # next row
      x = len(lst[0])-1-x   d  # move to other end of row
      
   if y == len(lst) or y == -1:  # end or array
      d=-d  # switch direction
      y =d  # start back
      x = len(lst[0])-1-x   d  # revert other end of row
   ctr =1
   showgrid(lst)
   time.sleep(.1)
  

Вывод

  0   0   0
 0   1   0
 0   0   0

 0   0   0
 0   1   2
 0   0   0

 0   0   0
 0   1   2
 3   0   0

 0   0   0
 0   1   2
 3   4   0

 0   0   0
 0   1   2
 3   4   5

 0   0   0
 0   1   2
 3   6   5

 0   0   0
 0   1   2
 7   6   5

 0   0   0
 0   1   8
 7   6   5

 0   0   0
 0   9   8
 7   6   5

 0   0   0
 10  9   8
 7   6   5
  

Ответ №3:

В отличие от других подходов, я решил сначала получить диапазон всех возможных x и y (включая цикл и обратный цикл), используя get_range_positions функцию. После этого я выполнил другую функцию для получения необходимых значений, учитывая начальную позицию для x и y, и эту функцию я вызвал get_coordinates .

В конце я просматриваю список, учитывая полученные значения x и y .

 def get_range_positions(len_first_list,
                        len_second_list):

    result = []

    # loop

    for a in range(len_first_list):
        for b in range(len_second_list):
            result.append((a,b))

    # reverse loop, but we don't want
    # the last and first value again

    f = 0
    l = len(result) - 2

    for i in result[l:f:-1]:
        result.append(i)

    return result


def get_coordinates(start_x,start_y, range_positions):

    # finding out where start_x and start_y is in range_positions
    start = range_positions.index((start_x,start_y))

    # Return X and Y from (start_x,start_y) until the end
    for i in range_positions[start:]:
        yield i[0], i[1]

    # Return X and Y for the entire result_changes, forever.
    while True:
        for i in range_positions:
            yield i[0], i[1]


lst = [[x for x in range(6)] for y in range(6)]
range_positions = get_range_positions(6,6)
print(range_positions)

for x, y in get_coordinates(start_x=0,
                            start_y=0,
                            range_positions=range_positions):

    lst[x,y] = do something
  

Ответ №4:

Вы могли бы создать плоскую одномерную последовательность индексов для вашего 2D-списка:

 indices1D = [(i, j) for i in range(NROWS) for j in range(NCOLUMNS)]
  

Чтобы иметь возможность вернуться назад, прикрепите обратные индексы и используйте itertools.cycle() , чтобы повторять это вечно:

 import itertools

indices = itertools.cycle(indices1d   indices1d[::-1][1:-1])
  

[1:-1] выше указано, чтобы сократить / избежать дублирования точек поворота.

Чтобы начать с заданного индекса, вы могли бы использовать itertools.islice :

 start_position = i_start * NCOLUMNS   j_start
for i, j in itertools.islice(indices, start_position, None):
    print(lst[i][j])
  

Собрать все это вместе:

 import itertools


def back_n_forth(seq, i_start, j_start):
    indices1d = [(i, j) for i in range(NROWS) for j in range(NCOLUMNS)]
    indices = itertools.cycle(indices1d   indices1d[::-1][1:-1])
    start_position = i_start * NCOLUMNS   j_start
    for i, j in itertools.islice(indices, start_position, None):
        yield seq[i][j]

# some random 2d list
NROWS = 3
NCOLUMNS = 2
lst = [
    [chr(ord('a')   i)   str(j) for j in range(NCOLUMNS)]
    for i in range(NROWS)
]
for row in lst:
    print(*row)
print()    

# look at the first few items in the infinite sequence
for x in itertools.islice(back_n_forth(lst, 1, 0), 20):
    print(x, end=' ')
  

Вывод

 a0 a1
b0 b1
c0 c1

b0 b1 c0 c1 c0 b1 b0 a1 a0 a1 b0 b1 c0 c1 c0 b1 b0 a1 a0 a1