Reorganizing a matrix (list of lists) using only lists
Consider the following 3 x 4 matrix, implemented as a list of 3 lists of length 4 in Python:
>>> matrix = [[1, 2, 3, 4],[5, 6, 7, 8],[9, 10, 11, 12]]
The following list comprehension will change the matrix that translates rows and columns:
>>> [[row[i] for row in matrix] for i in range(4)]
[[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]
BUT I need to do this as a result:
[[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]]
which is a rebuilt 4 x 3 matrix to get a sequential "scroll" of the original matrix, which is "split" into a new row every 3 elements.
I know it is possible to work out an algorithm to achieve the task, but could one get it using just a list comprehension? (And if so, how?)
EDIT:
The accepted answer must meet the following requirements:
- should work on a basic / clean Python installation (no additional libraries);
- should be (similar to moving a matrix) "one-line".
2nd EDIT + Accepted answer motivation:
Here's what I did when I needed to find a solution for this (based on the suggestions I gave in my own comments below):
mat = [[1,2,3,4],[5,6,7,8],[9,10,11,12]]
[[mat[(3*(i-1)+j -1)//4+1][(3*(i-1)+j -1)%4] for j in range(3)] for i in range(4)]
NOTE that the solution I wrote is specific to this case, but as Claudion noted, the "formula" can be "generalized" to reset the original matrix (list of lists) to different "shapes".
source to share
How about something like this:
>>> matrix = [[1, 2, 3, 4],[5, 6, 7, 8],[9, 10, 11, 12]]
>>> it = (y for x in matrix for y in x)
>>> list(zip(*[it]*3))
[(1, 2, 3), (4, 5, 6), (7, 8, 9), (10, 11, 12)]
If you want a list of lists:
>>> matrix = [[1, 2, 3, 4],[5, 6, 7, 8],[9, 10, 11, 12]]
>>> it = (y for x in matrix for y in x)
>>> list(map(list, zip(*[it]*3)))
[[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]]
Explanation:
-
First, we create a generator that gives the elements of the list (as if it were flattened with a single list, i.e. 1,2,3,4,5,6, ..., 12) - we store that in
it
. -
Then we call
zip()
three times; since the generator is the same, it provides the next item in theit
.
FURTHER NOTE: you can even reinstall the original matrix in different "shapes" than 4 x 3 if you want, just changing 3
to the number of columns you want . (For example, change it to 2
or to 6
and you get a replacement instead of 6 x 2 or 2 x 6).
Method without using zip
and only using list comprehension, but it requires two lines -
>>> matrix = [[1, 2, 3, 4],[5, 6, 7, 8],[9, 10, 11, 12]]
>>> it = (y for x in matrix for y in x)
>>> [[next(it) for _ in range(3)] for _ in range(4)]
[[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]]
source to share
Is numpy an option?
import numpy x = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]] y = numpy.array(x).reshape((4, 3)) print y
Output:
[[ 1 2 3]
[ 4 5 6]
[ 7 8 9]
[10 11 12]]
Here, at least in list comprehension, I am lacking creativity right now, but this does the trick somewhat: P
print [[[z for y in x for z in y][i*3+j] for j in range(len(x))] for i in range(len(x[0]))]
Output:
[[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]]
source to share
The following solution only uses lists, not zip:
m = [[1, 2, 3, 4],[5, 6, 7, 8],[9, 10, 11, 12]]
flat = [l2 for l1 in m for l2 in l1]
output = [[flat.pop(0), flat.pop(0), flat.pop(0)] for x in range(4)]
print(output)
Output:
[[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]]
Or for a very simple one liner:
print [m[0][:3],[m[0][3]]+m[1][0:2],m[1][2:]+[m[2][0]],m[2][1:]]
source to share
Well, with lists only, this is rough (suggestions would be appreciated?):
matrix = [[1, 2, 3, 4],[5, 6, 7, 8],[9, 10, 11, 12]]
lst = [y for row in matrix for y in row]
lst = [[lst[x+y*3] for x in range(3)] for y in range(4)]
print(lst)
Result:
[[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]]
Yes! In one sense of the list:
nr, nc = 4, 3
ic = len(matrix[0])
lst = [[matrix[(r*nc+c)//ic][(r*nc+c)%ic] for c in range(nc)] for r in range(nr)]
print(*lst, sep="\n")
Result:
[1, 2, 3]
[4, 5, 6]
[7, 8, 9]
[10, 11, 12]
But you can also have (s nr, nc = 6, 2
)
[1, 2]
[3, 4]
[5, 6]
[7, 8]
[9, 10]
[11, 12]
What's your question, no?
source to share