9

this is my first post, i'm pretty new this awesome site.

i'd like to list all elements in a 3x3 array diagonally:

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

expected output:

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

Also, how would I generalize it to any N x N array?

Edit: I've noticed this has been asked before yet i'm looking for a way without importing numpy or any library for that matter.

Edit2: One of my classmates offered this solution, I like it the most:

Since you finding diagonals starting from the bottom left corner, you could do this by starting in the top right corner of the square and reversing your solution in the end. My approach was first reversing each row in L, and then appending each element to its corresponding diagonal list. The insight here is that you start appending elements in each row K not in the first sub-list of the final list, but starting at indice K. For instance after reversing row [4,5,6] to row [6,5,4], I would append 6 to the 2nd sublist of my diagonally ordered list (since this is the 2nd row), then I would append 5 to the 3rd sublist, and then I would append 4 to the fourth sublist. However, if I didn't have a fourth sublist at the moment in time in my diagonal list, I would add a fourth empty list, then fill it with 4.

My explanation may not be too clear, so here's the code I have.

def diagonal(l):

    L = l[:]
    return_list = [[] for i in range(len(L))]

    for line in range(len(L)):
        L[line].reverse()
        i = line

        for elem in L[line]:
            if i >= len(return_list):
                return_list.append([])

            return_list[i].append(elem)
            i += 1

    return_list.reverse()
    return return_list
Moe
  • 99
  • 1
  • 3
  • I made a way to do this for a program a while back which doesn't use numpy. I'll add it to http://stackoverflow.com/questions/6313308/get-all-the-diagonals-in-a-matrix-list-of-lists-in-python – flakes Apr 14 '14 at 20:29
  • 1
    @Calpratt Thanks! i've had to read your solution 3 times to understand it but I finally get it ;D – Moe Apr 14 '14 at 22:10

1 Answers1

15

Using only Python (no NumPy):

import itertools as IT

L = [  [1, 2, 3],
       [4, 5, 6],
       [7, 8, 9] ]
N = len(L)
d = dict()
for i,j in IT.product(range(N), repeat=2):
    d.setdefault(j-i, []).append((i,j))

print([[L[i][j] for i,j in d[k]] for k in range(-N+1, N)])    
# [[7], [4, 8], [1, 5, 9], [2, 6], [3]]

Or, even better, use Nemo's transformation (generalized to h x w shaped matrices:

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

h, w = len(L), len(L[0])

print([[L[h-1-q][p-q]
        for q in range(min(p, h-1), max(0, p-w+1)-1, -1)]
       for p in range(h+w-1)])                             
# [[7], [4, 8], [1, 5, 9], [2, 6], [3]]

We can also put this code in a function for easier usage:

def diagonals(L):
    """
    https://stackoverflow.com/a/31373955/190597 (unutbu)
    >>> L = array([[ 0,  1,  2],
                   [ 3,  4,  5],
                   [ 6,  7,  8],
                   [ 9, 10, 11]])

    >>> diagonals(L)
    [[9], [6, 10], [3, 7, 11], [0, 4, 8], [1, 5], [2]]
    """
    h, w = len(L), len(L[0])
    return [[L[h - p + q - 1][q]
             for q in range(max(p-h+1, 0), min(p+1, w))]
            for p in range(h + w - 1)]


def antidiagonals(L):
    """
    >>> L = array([[ 0,  1,  2],
                   [ 3,  4,  5],
                   [ 6,  7,  8],
                   [ 9, 10, 11]])

    >>> antidiagonals(L)
    [[0], [3, 1], [6, 4, 2], [9, 7, 5], [10, 8], [11]]
    """
    h, w = len(L), len(L[0])
    return [[L[p - q][q]
             for q in range(max(p-h+1,0), min(p+1, w))]
            for p in range(h + w - 1)]
Community
  • 1
  • 1
unutbu
  • 842,883
  • 184
  • 1,785
  • 1,677
  • Great answer. How can I convert the matrix back to the original form (diagonal -> matrix) after performing the operations that I wanted to perform on the diagonals? – bimbi Jun 01 '21 at 03:38