1

So I had to write a code to find all the diagonal strings in a grid mystery

mystery = [["r","a","w","b","i","t"],
           ["x","a","y","z","c","h"],
           ["p","q","b","e","i","e"],
           ["t","r","s","b","o","g"],
           ["u","w","x","v","i","t"],
           ["n","m","r","w","o","t"]]

And here is what I have so far, with the help of a few experts because I'm new to this. The expert who helped me is https://stackoverflow.com/users/5237560/alain-t

def diagsDownRight(M):
    diags,pad = [],[]
    while any(M):
        edge = [*next(zip(*reversed(M))),*M[0][1:]]
        M    = [r[1:] for r in M[1:]]
        diags.append(pad+edge+pad)
        pad.append("")
    return [*map("".join,zip(*diags))]

While this does work, I myself find it hard to grasp and I do not want to just write down a code that I do not understand. So, can anyone please help make the code as basic as possible?

When I mean basic as possible, I mean like picture yourself as a person who has just learnt coding for a couple of months, and please try to simplify my code as much as possible.

Bruffff
  • 53
  • 7
  • 2
    Are the diagonals just the two 6 long diagonals from top left to bottom right, top right to bottom left? Or every single diagonal within the board? – Larry the Llama Nov 07 '21 at 01:47
  • 5
    This is not simple code, nor a simple algorithm. Admit it, your experts wrote it for you, it was not "with the help of...". I find it hard to grasp at first reading, and I have worked with python for quite a few years. It would be nice if they commented their code. – RufusVS Nov 07 '21 at 01:49
  • 1
    also, just a note but the solution included above appears to be from [here](https://stackoverflow.com/a/69867077/10237506); I'll admit the code is quite confusing as it is, tbh. – rv.kvetch Nov 07 '21 at 01:57
  • Does this answer your question? [Get all the diagonals in a matrix/list of lists in Python](https://stackoverflow.com/questions/6313308/get-all-the-diagonals-in-a-matrix-list-of-lists-in-python) – SuperStormer Nov 07 '21 at 01:59
  • 2
    Speaking quite honestly, but if I saw this being used in production code maybe on a team I was working on, I'd probably run away as fast as I can. So I definitely agree with OP on this at least. – rv.kvetch Nov 07 '21 at 02:04

3 Answers3

4

The easiest I could think of: pad rows so that diagonals become columns. The code:

def diagsDownRight(M): 
    n = len(M)
    m = [[''] * (n-i-1) + row + [''] * i for i, row in enumerate(M)]  # pad rows 
    return [''.join(col) for col in zip(*m)] 

The result is the same, and IMO the approach is more intuitive

Marat
  • 15,215
  • 2
  • 39
  • 48
  • thank you for taking ur time off to help me. btw if we want to do from the left side down, do we use m = [[''] * (n+i+1) or smth? – Bruffff Nov 07 '21 at 03:29
  • @Bruffff yeah, same thing just `n-i-1` and `i` switched: `m = [['']*i + row + ['']*(n-i-1) for i, row in enumerate(M)]` – Marat Nov 07 '21 at 03:36
  • also one more quick question, what if we want to print like backwards. Like from the code that u provided the values are printed from top to bottom like n, um, twr and so on.. but if I want to print out from bottom to top like n, mu, rwt and so on, can I do return return (reversed[''.join(col) for col in zip(*m)] ) or is there another solution? – Bruffff Nov 07 '21 at 04:38
  • 1
    @Bruffff in the last line, reverse col: `''.join(reversed(col))` – Marat Nov 07 '21 at 13:53
2

consider a square matrix

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

the indexes into the diagonals are as follows

d1 = [[0,0],[1,1],[2,2]]
d2 = [[0,1],[1,2]]
d3 = [[1,0],[2,1]]
d4 = [[2,0]]
d5 = [[0,2]]

to get the middle diagonal you can simply start with the indexes

for i in range(3):
    index = [i,i]

for the next diagonal we simply do the same... but offset x by 1, until we go out of bounds

for i in range(3):
   if i + 1 > 2:
      break
   index = [i, i+1]

for the next diagonal its the same ... except we do it on the other axis

for i in range(3):
   if i + 1 > 2:
      break
   index = [i + 1, i]

for the toprightmost (in this case ...) its the same but we add 2

 for i in range(3):
   if i + 2 > 2:
      break
   index = [i, i+2]

same for the bottom most but using the other index

 for i in range(3):
   if i + 2 > 2:
      break
   index = [i + 2, i]

I will leave it to you to extrapolate this into a working solution

Joran Beasley
  • 110,522
  • 12
  • 160
  • 179
1

here's a simpler version:

def diagsDownRight(M):
    rows = len(M)      # number of rows
    cols = len(M[0])   # number of columns
    result   = []      # result will be a list of strings
    leftSide = [(r,0) for r in range(rows)]   # first column
    topSide  = [(0,c) for c in range(1,cols)] # first row
    for r,c in leftSide[::-1] + topSide:      # all start positions
        s = "" # string on the diagonal
        while r < rows and c < cols:
            s += M[r][c]  # accumulate characters
            r += 1        # move down
            c += 1        # and to the right
        result.append(s)  # add diagonal string to result
    return result

print(diagsDownRight(mystery))
['n', 'um', 'twr', 'prxw', 'xqsvo', 
 'rabbit', 'ayeot', 'wzig', 'bce', 'ih', 't']

The way it works is by starting at the coordinate of the left and top positions, accumulate characters going one place to the right and down until going out of the matrix.

I would suggest you go with Marat's solution though. It is simple and elegant. If you print the m matrix I'm sure, you'll understand what's going on

Alain T.
  • 40,517
  • 4
  • 31
  • 51