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".

+3


source to share


4 answers


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 the it

    .

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]]

      

+3


source


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]]

      

+2


source


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:]]

      

+2


source


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?

+1


source







All Articles