1

I have a simple list of lists called square:

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

and my goal is to iterate through each of the nine elements and get all the values in that element's row and column simultaneously. In this example, the first iteration (for element 1) should return [1,2,3] and [1,4,7], the second (for element 2) would give me [1,2,3] and [2,5,8], etc. The following code works:

for r in range(3):
    for c in range(3):
        row = square[r]
        col = [square[c1][c] for c1 in range(3)]

but is there another method using base Python to do this?

I can transpose and iterate over the list using for c in zip(*square):, which works if I just need the columns once, but is there no way to use array slicing to index the columns without storing the transpose of the matrix as well as the matrix itself?

Unfortunately, libraries like numpy aren't an option at the moment because they'll need to go through our code review process first, which takes a long time (on the order of six months...). I didn't write the policy or design the procedures, but it's the policy I have to work with at this institution. I already filed the request for numpy, but in the meantime, I'm just using base Python.

John Bensin
  • 301
  • 2
  • 5
  • 20
  • 4
    use [numpy](http://www.numpy.org/) – JBernardo Apr 23 '13 at 21:54
  • @JBernardo See my edit. I already put in the request for a code review process on numpy, but it usually takes a *long* time, so in the meantime I'm hoping for ideas that use base Python. – John Bensin Apr 23 '13 at 21:58
  • @MartijnPieters The implication being that I transpose the array and keep two copies of it (the original and the transpose) and then iterate through those, right? I knew how to transpose the array, but since I'm already iterating through it element-by-element, I assumed there might be another way I wasn't aware of. – John Bensin Apr 23 '13 at 22:02
  • 1
    Just iterate directly over `zip(*square)` whenever you need to have per-column access. – Martijn Pieters Apr 23 '13 at 22:03
  • @MartijnPieters Hmmm, I'll have to work that out, since I need both row and column access simultaneously and for each element; I don't just need to fetch each column once. That should be trivial if I iterate over both `square` and `zip(*square)` at the same time, though. – John Bensin Apr 24 '13 at 03:02

2 Answers2

4

using numpy

>>> import numpy as np
>>> square = np.array([[1,2,3],[4,5,6],[7,8,9]])
>>> square[0]
array([1, 2, 3])
>>> square[..., 0]
array([1, 4, 7])
>>> square[:, 0]
array([1, 4, 7])

Using just Python

>>> square = [[1,2,3],[4,5,6],[7,8,9]]
>>> square[0]
[1, 2, 3]
>>> zip(*square)[0]
(1, 4, 7)
John La Rooy
  • 295,403
  • 53
  • 369
  • 502
  • I'm anxiously awaiting the day our code review process finishes and I can use this. It seems so much easier (and more MATLABesque) than the alternatives. Unfortunately, numpy isn't an option for me at the moment. – John Bensin Apr 24 '13 at 03:03
  • Even though my question was more than just transposing the matrix, I ended up using `zip(*square)`, storing the transpose, and iterating through each element. It's more than just the transpose because I need the rows and the columns simultaneously, but I can add my little code snippet to the bottom of your answer and accept it, so the base and numpy solutions are in the same place. – John Bensin Apr 24 '13 at 20:12
1

If you want to do this with standard Python, you might want to try transposing the list. You can then index as normal. You can do this with zip(*square) followed by map(list,) to turn it back into a list:

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

square_transposed = map(list, zip(*square))

Then square[1] will get you [2,5,8].

If you're wondering what the * operator is doing in this context, it unpacks the list to a series of position arguments. So zip sees [1,2,3] [4,5,6] [7,8,9] and zips them together as [(1, 4, 7), (2, 5, 8), (3, 6, 9)]. Then the final map turns the tuples to lists.

Community
  • 1
  • 1
mfitzp
  • 15,275
  • 7
  • 50
  • 70
  • Basically, just maintain two copies of the data as I index through? – John Bensin Apr 23 '13 at 21:59
  • I'm not sure there is another way. You might want to create a class to handle this for you - you could cache the transformed version within the same object, depending if memory or speed are your main priorities. – mfitzp Apr 23 '13 at 22:10
  • Unfortunately I think you have to wrap the `map` with another `list` call. Try having this as an alternative: `[list(x) for x in zip(*square)]`. – squiguy Apr 23 '13 at 22:18