65

リストのリストとして表される (正方) 行列のすべての対角線を取得する Pythonic の方法を探しています。

次のマトリックスがあるとします。

matrix = [[-2,  5,  3,  2],
          [ 9, -6,  5,  1],
          [ 3,  2,  7,  3],
          [-1,  8, -4,  8]]

次に、大きな対角線は簡単です。

l = len(matrix[0])
print([matrix[i][i] for i in range(l)])              # [-2, -6, 7,  8]
print([matrix[l-1-i][i] for i in range(l-1,-1,-1)])  # [ 2,  5, 2, -1]

しかし、すべての対角線を生成する方法が思いつきません。私が探している出力は次のとおりです。

[[-2], [9, 5], [3,-6, 3], [-1, 2, 5, 2], [8, 7, 1], [-4, 3], [8],
 [2], [3,1], [5, 5, 3], [-2, -6, 7, 8], [9, 2, -4], [3, 8], [-1]]
4

14 に答える 14

64

以下よりもnumpyでそれを行うためのより良い方法がおそらくありますが、私はまだあまり慣れていません:

import numpy as np

matrix = np.array(
         [[-2,  5,  3,  2],
          [ 9, -6,  5,  1],
          [ 3,  2,  7,  3],
          [-1,  8, -4,  8]])

diags = [matrix[::-1,:].diagonal(i) for i in range(-3,4)]
diags.extend(matrix.diagonal(i) for i in range(3,-4,-1))
print [n.tolist() for n in diags]

出力

[[-2], [9, 5], [3, -6, 3], [-1, 2, 5, 2], [8, 7, 1], [-4, 3], [8], [2], [3, 1], [5, 5, 3], [-2, -6, 7, 8], [9, 2, -4], [3, 8], [-1]]

編集:任意の行列サイズに一般化するように更新されました。

import numpy as np

# Alter dimensions as needed
x,y = 3,4

# create a default array of specified dimensions
a = np.arange(x*y).reshape(x,y)
print a
print

# a.diagonal returns the top-left-to-lower-right diagonal "i"
# according to this diagram:
#
#  0  1  2  3  4 ...
# -1  0  1  2  3
# -2 -1  0  1  2
# -3 -2 -1  0  1
#  :
#
# You wanted lower-left-to-upper-right and upper-left-to-lower-right diagonals.
#
# The syntax a[slice,slice] returns a new array with elements from the sliced ranges,
# where "slice" is Python's [start[:stop[:step]] format.

# "::-1" returns the rows in reverse. ":" returns the columns as is,
# effectively vertically mirroring the original array so the wanted diagonals are
# lower-right-to-uppper-left.
#
# Then a list comprehension is used to collect all the diagonals.  The range
# is -x+1 to y (exclusive of y), so for a matrix like the example above
# (x,y) = (4,5) = -3 to 4.
diags = [a[::-1,:].diagonal(i) for i in range(-a.shape[0]+1,a.shape[1])]

# Now back to the original array to get the upper-left-to-lower-right diagonals,
# starting from the right, so the range needed for shape (x,y) was y-1 to -x+1 descending.
diags.extend(a.diagonal(i) for i in range(a.shape[1]-1,-a.shape[0],-1))

# Another list comp to convert back to Python lists from numpy arrays,
# so it prints what you requested.
print [n.tolist() for n in diags]

出力

[[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]]

[[0], [4, 1], [8, 5, 2], [9, 6, 3], [10, 7], [11], [3], [2, 7], [1, 6, 11], [0, 5, 10], [4, 9], [8]]
于 2011-06-11T01:01:38.967 に答える
22

右上に傾斜する対角線から始めます。

(x,y) が行列内の直交座標である場合、座標スキーム (p,q) との間で変換する必要があります。ここで、p は対角線の数、q は対角線に沿ったインデックスです。(したがって、p=0 は [-2] 対角、p=1 は [9,5] 対角、p=2 は [3,-6,3] 対角などです。)

(p,q) を (x,y) に変換するには、次を使用できます。

x = q
y = p - q

p と q の値を差し込んでみて、これがどのように機能しているかを確認してください。

これで、ループするだけです... 0 から 2N-1 までの p と、max(0, p-N+1) から min(p, N-1) までの q の場合。p,q を x,y に変換して出力します。

次に、他の対角線について、ループを繰り返しますが、別の変換を使用します。

x = N - 1 - q
y = p - q

(これは事実上、マトリックスを左右反転させるだけです。)

申し訳ありませんが、実際にはこれを Python でコーディングしていません。:-)

于 2011-06-11T00:59:42.753 に答える
17

これは、同様の質問Moeをした さん向けです。

長方形の行列の行または列をコピーする単純な関数を作成することから始めます。

def get_rows(grid):
    return [[c for c in r] for r in grid]

def get_cols(grid):
    return zip(*grid)

これらの 2 つの関数を使用して、各行の開始/終了に増加/減少バッファーを追加して対角線を取得します。次に、このバッファリングされたグリッドの列を取得し、その後、各列のバッファを削除します。すなわち)

1 2 3    |X|X|1|2|3|    | | |1|2|3|
4 5 6 => |X|4|5|6|X| => | |4|5|6| | => [[7],[4,8],[1,5,9],[2,6],[3]]
7 8 9    |7|8|9|X|X|    |7|8|9| | |

.

def get_backward_diagonals(grid):
    b = [None] * (len(grid) - 1)
    grid = [b[i:] + r + b[:i] for i, r in enumerate(get_rows(grid))]
    return [[c for c in r if c is not None] for r in get_cols(grid)]

def get_forward_diagonals(grid):
    b = [None] * (len(grid) - 1)
    grid = [b[:i] + r + b[i:] for i, r in enumerate(get_rows(grid))]
    return [[c for c in r if c is not None] for r in get_cols(grid)]
于 2014-04-14T20:37:08.550 に答える
8

最近、この車輪を再発明しました。リストの正方形のリストで対角線を見つけるための再利用/拡張が簡単な方法を次に示します。

def get_diagonals(grid, bltr = True):
  dim = len(grid)
  assert dim == len(grid[0])
  return_grid = [[] for total in xrange(2 * len(grid) - 1)]
  for row in xrange(len(grid)):
    for col in xrange(len(grid[row])):
      if bltr: return_grid[row + col].append(grid[col][row])
      else:    return_grid[col - row + (dim - 1)].append(grid[row][col])
  return return_grid

リストのインデックスを仮定します:

00 01 02 03

10 11 12 13

20 21 22 23

30 31 32 33

設定するbltr = Trueと (デフォルト)、左下から右上への対角線が返されます。

00           # row + col == 0
10 01        # row + col == 1
20 11 02     # row + col == 2
30 21 12 03  # row + col == 3
31 22 13     # row + col == 4
32 23        # row + col == 5
33           # row + col == 6

setting bltr = False、左下から右上への対角線を返します。つまり

30            # (col - row) == -3
20 31         # (col - row) == -2
10 21 32      # (col - row) == -1
00 11 22 33   # (col - row) == 0
01 12 23      # (col - row) == +1
02 13         # (col - row) == +2
03            # (col - row) == +3

これは、 OP の入力マトリックスを使用した実行可能なバージョンです。

于 2017-08-02T20:11:23.737 に答える
1

これは、幅と高さが等しい行列に対してのみ機能します。 しかし、サードパーティにも依存していません。

matrix = [[11, 2, 4],[4, 5, 6],[10, 8, -12]]

# only works for diagnoals of equal width and height
def forward_diagonal(matrix):
    if not isinstance(matrix, list):
        raise TypeError("Must be of type list")

    results = []
    x = 0
    for k, row in enumerate(matrix):
        # next diag is (x + 1, y + 1)
        for i, elm in enumerate(row):

            if i == 0 and k == 0:
                results.append(elm)
                break
            if (x + 1 == i):
                results.append(elm)
                x = i
                break
    return results

print 'forward diagnoals', forward_diagonal(matrix)
于 2015-10-30T14:16:00.227 に答える
-1

ここから:np.Diagonal

 np.diagonal(matrix)
于 2021-06-16T18:21:10.240 に答える