Обход змеи двумерного массива NumPy - PullRequest
5 голосов
/ 14 апреля 2019

У меня есть следующий 2D-массив:

In [173]: arr
Out[173]: 
array([[ 1,  2,  3,  4],   # -> -> -> ->
       [ 5,  6,  7,  8],   # <- <- <- <-
       [ 9, 10, 11, 12],   # -> -> -> ->
       [13, 14, 15, 16],   # <- <- <- <-
       [17, 18, 19, 20]])  # -> -> -> ->

И я хотел бы пройти массив в змееподобном образце , начиная с левого верхнего элемента и заканчивая правым нижним элементом.

На данный момент у меня есть такой неинтересный способ решения:

In [187]: np.hstack((arr[0], arr[1][::-1], arr[2], arr[3][::-1], arr[4]))
Out[187]: 
array([ 1,  2,  3,  4,  8,  7,  6,  5,  9, 10, 11, 12, 16, 15, 14, 13, 17,
       18, 19, 20])

Как мы можем сделать это с минимальными усилиями, без зацикливания и не слишком много жесткого кодирования?

1 Ответ

4 голосов
/ 14 апреля 2019

Один из способов - начать с копии входных данных, а затем заменить вторую строку и далее вернувшейся версией соответствующих строк из входных данных и сделать это для всех четных строк, используя пошаговое нарезание. Наконец, ravel() необходимо в конце для желаемой плоской версии.

Следовательно, реализация будет выглядеть примерно так -

out = arr.copy()
out[1::2] = arr[1::2,::-1]
out = out.ravel()

Другим компактным способом было бы с np.where сделать выбор между вариантами с переворотом и без переворота и, следовательно, достичь желаемого результата -

np.where(np.arange(len(arr))[:,None]%2,arr[:,::-1],arr).ravel()

Пояснение к данному образцу -

# Array to be used for the chosing. 1s would be True ones and 0s are False
In [72]: np.arange(len(arr))[:,None]%2
Out[72]: 
array([[0],
       [1],
       [0],
       [1],
       [0]])

# Use np.where to choose. So, arr[:,::-1] must be the first data, as
# that's one to be put on even rows and arr would be the second one.
In [73]: np.where(np.arange(len(arr))[:,None]%2,arr[:,::-1],arr)
Out[73]: 
array([[ 1,  2,  3,  4],
       [ 8,  7,  6,  5],
       [ 9, 10, 11, 12],
       [16, 15, 14, 13],
       [17, 18, 19, 20]])

# Finally flatten
In [74]: np.where(np.arange(len(arr))[:,None]%2,arr[:,::-1],arr).ravel()
Out[74]: 
array([ 1,  2,  3,  4,  8,  7,  6,  5,  9, 10, 11, 12, 16, 15, 14, 13, 17,
       18, 19, 20])
...