Самая быстрая итерация по двум измерениям в python - PullRequest
0 голосов
/ 02 апреля 2020

Какой самый быстрый способ перебора двухмерного массива в python? Учитывая, что мне всегда нужны индексы x и y.

Например, у меня есть этот код, который пытается «сопоставить» 3 одинаковых числа в матрице, если они являются числами 2, 3, 4, 5 или 6. :

for x in range(matrix.shape[0]):
    for y in range(matrix.shape[1]):
        if matrix[x][y] == 2 or matrix[x][y] == 3 or matrix[x][y] == 4 or matrix[x][y] == 5 or matrix[x][y] == 6: ## if i find one of the numbers i need
            fuseNumber = matrix[x][y] ## lets get that number
            if matrix[x+1][y] == fuseNumber: ## if we find another of that to the bottom of the initial one, we should try to find a third one
                if matrix[x-1][y] == fuseNumber: ## if we find another one at the top from the initial one
                    matrix[x][y] = 0
                    matrix[x+1][y] = 0
                    matrix[x-1][y] = 0
                    ...

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

it = numpy.nditer(matrix, flags=['multi_index'])
while not it.finished:
    x = it.multi_index[0]
    y = it.multi_index[1]
    if matrix[x][y] == 2 or matrix[x][y] == 3 or matrix[x][y] == 4 or matrix[x][y] == 5 or matrix[x][y] == 6:
        fuseNumber = matrix[x][y] ## lets get that fuse number, whichever it may be!
        if matrix[x+1][y] == fuseNumber: ## if we find another of that to the bottom of the initial one, we should try to find a third one
            if matrix[x-1][y] == fuseNumber: ## if we find another one at the top from the initial one  ///////  center bottom top
                matrix[x][y] = 0
                matrix[x+1][y] = 0
                matrix[x-1][y] = 0
                ...
it.iternext()

Но использование timeit.timeit () показало, что второй код на самом деле медленнее. Несмотря на эти два примера, как бы вы написали один и тот же код, но с максимальной производительностью?

Спасибо!

1 Ответ

0 голосов
/ 02 апреля 2020

Вместо того, чтобы искать, используя ваш двойник для l oop:

for x in range(matrix.shape[0]):
    for y in range(matrix.shape[1]):
        if matrix[x][y] == 2 or matrix[x][y] == 3 or matrix[x][y] == 4 or matrix[x][y] == 5 or matrix[x][y] == 6: ## if i find one of the numbers i need
            fuseNumber = matrix[x][y] ## lets get that fuse number,
         ...

Вы можете искать, используя где пример

Это позволяет зацикливать только значения x, y в требуемом диапазоне.

for x, y in zip(*np.where(np.logical_and(matrix>=2, matrix<=6))):
    fuseNumber = matrix[x][y] ## lets get that fuse number,
         ...

Проверка

Проверка того, что оба метода создают один и тот же x , у пар

# Random matrix (5, 10) with numbers between 0 & 10
matrix = np.random.randint(0, 10,  size=(5, 10))

# OP method
set_for = set()
for x in range(matrix.shape[0]):
    for y in range(matrix.shape[1]):
      if 2 <= matrix[x][y] <= 6:
        set_for.add((x, y))

# Method using where
set_numpy = set((x, y) for x, y in zip(*np.where(np.logical_and(matrix>=2, matrix<=6))))

# Result
print(set_for == set_numpy)

Выход

True
...