[Tutor] getting diagonals from a matrix

Emile van Sebille emile at fenx.com
Wed Mar 3 17:30:35 CET 2010


On 3/2/2010 2:54 PM David Eccles (gringer) said...
> I've managed to drum up some code to obtain a list containing joined diagonal
> elements of a matrix (I'm making a word finder generator), but am wondering if
> there's any better way to do this:

This works.  Lots of other ways would work too.  What would make one 
better than another?  Anyway, here's my take on it...

#<pasteable_code>

# setup so code snippet works properly
sizeW = 4
sizeH = 3
puzzleLayout = ['spam'] * (sizeW * sizeH)

# this allows the result to match your example

from string import digits,letters
puzzleLayout = (digits+letters)[:sizeW * sizeH]


# Starting with, say, an array with these indices:

# It might help to consider the indices numbers as that's what
# python does, so I've assumed these to be the values instead.

# 0 1 2 3
# 4 5 6 7
# 8 9 A B

# Looking at the index table above, note that all the results
# start on an edge and work diagonally from there.  I'll guess
# you found the back diags easier -- no messy 'in-the-same-row'
# problems -- but the forward diags are harder.  Note if we
# flype the table the forward diags can be built from the back
#
diag instructions

#FpuzzleLayout
# 8 9 A B
# 4 5 6 7
# 0 1 2 3

# so we'll build it once like this...
FpuzzleLayout = "".join(
   [ puzzleLayout[ii-sizeW:ii]
     for ii in range(sizeW*sizeH,0,-sizeW)
     ] )

#So now, the only starting positions we need to worry about are
# on the left and top edge ignoring the start and end corners.
edge = (range(sizeW * sizeH,0,-sizeW)+range(sizeW-1))[2:]

# and to avoid any modular impact, we'll add a length constraint
lens = range(2,sizeH+1)+range(sizeW-1,1,-1)

# and do it
result = []

for ii,ln in zip(edge,lens):
   result.append(puzzleLayout[ii::sizeW+1][:ln])
   result.append(FpuzzleLayout[ii::sizeW+1][:ln])


# now add in the reversed results
for ii in result[:]:
   result.append("".join(reversed(ii)))

# and the corners
result.extend([puzzleLayout[0],
                puzzleLayout[-1],
                FpuzzleLayout[0],
                FpuzzleLayout[-1]])


#</pasteable_code>

Emile

>
> # I want the following items for a back diagonal (not in square brackets):
> # [-2],[3],8 (+5) | div 4 = -1, 1, 2
> # [-1],4,9 (+5)   | div 4 = -1, 1, 2
> # 0,5,A (+5)      | div 4 =  0, 1, 2
> # 1,6,B (+5)      | div 4 =  0, 1, 2
> # 2,7,[C] (+5)    | div 4 =  0, 1, 3
> # 3,[8],[D] (+5)  | div 4 =  0, 2, 3
>
> # in other words, increase sequence by sizeW + 1 each time (sizeW - 1
> # for forward diagonals), only selecting if the line you're on matches
> # the line you want to be on
>
> # back as in backslash-like diagonal
> puzzleDiagBack = [(''.join([puzzleLayout[pos*(sizeW+1) + i] \
> for pos in range(sizeH) if (pos*(sizeW+1) + i) / sizeW == pos])) \
> for i in range(-sizeH+1,sizeW)]
> puzzleDiagBackRev = [(''.join(reversed([puzzleLayout[pos*(sizeW+1) + i] \
> for pos in range(sizeH) if (pos*(sizeW+1) + i) / sizeW == pos]))) \
> for i in range(-sizeH+1,sizeW)]
> # fwd as in forwardslash-like diagonal
> puzzleDiagFwdRev = [(''.join([puzzleLayout[pos*(sizeW-1) + i] \
> for pos in range(sizeH) if (pos*(sizeW-1) + i) / sizeW == pos])) \
> for i in range(sizeW+sizeH-1)]
> puzzleDiagFwd = [(''.join(reversed([puzzleLayout[pos*(sizeW-1) + i] \
> for pos in range(sizeH) if (pos*(sizeW-1) + i) / sizeW == pos]))) \
> for i in range(sizeW+sizeH-1)]
>
> Cheers,
> David Eccles (gringer)
> _______________________________________________
> Tutor maillist  -Tutor at python.org
> To unsubscribe or change subscription options:
> http://mail.python.org/mailman/listinfo/tutor
>




More information about the Tutor mailing list