-1

From an initial list:

starting_list = [
    [1,2,3,        4,5,6,        7,8,9      ],
    [11,22,33,     44,55,66,     77,88,99   ],
    [111,222,333,  444,555,666,  777,888,999]
]

I would like to create a new list (either using a for loop or list comprehension) whose elements are the sub-lists of starting_list, grouped by three elements and starting at every third index:

grouped_by_3_elements = [
    [1,2,3,  11,22,33,  111,222,333],
    [4,5,6,  44,55,66,  444,555,666],
    [7,8,9,  77,88,99,  777,888,999]
]

I have managed the following, but not exactly what I am looking for

[ [1, 2, 3], [11, 22, 33], [111, 222, 333], [4, 5, 6], [44, 55, 66], [444, 555, 666], [7, 8, 9], [77, 88, 99], [777, 888, 999] ]

Thanks

••• UPDATE •••

For those who want to know what I did to arrive at my current solution:

lst = [
[1,2,3,4,5,6,7,8,9],
[11,22,33,44,55,66,77,88,99],
[111,222,333,444,555,666,777,888,999]
]

new_lst = []

for col in range(0, len(lst[0]), 3):
    for row in range(3):
        new_lst.append(lst[row][col:col+3])    

print(new_lst)

>>> [[1, 2, 3], [11, 22, 33], [111, 222, 333], [4, 5, 6], [44, 55, 66], [444, 555, 666], [7, 8, 9], [77, 88, 99], [777, 888, 999]]

Can I somehow arrive at my desired

[
[1,2,3,  11,22,33,  111,222,333],
[4,5,6,  44,55,66,  444,555,666],
[7,8,9,  77,88,99,  777,888,999]
]

without having to run my result (new_lst) through a separate loop in order to repack ?

ZwiTrader
  • 195
  • 1
  • 2
  • 12

3 Answers3

2

Changing yours just a little:

new_lst = []

for col in range(0, len(lst[0]), 3):
    inner = []
    for row in range(3):
        inner += lst[row][col:col+3]
    new_lst.append(inner)

Changing it a bit more:

new_lst = []

for col in range(0, len(lst[0]), 3):
    inner = []
    for row in lst:
        inner += row[col:col+3]
    new_lst.append(inner)

Older solution from before there was an indication for other sizes:

Similar to an ordinary transposition of a 3×3 matrix, just with slices in the rows:

a = starting_list
for i in range(3):
    si = slice(i*3, i*3+3)
    for j in range(i):
        sj = slice(j*3, j*3+3)
        a[i][sj], a[j][si] = a[j][si], a[i][sj]
Kelly Bundy
  • 23,480
  • 7
  • 29
  • 65
2

You can use sub ranges in a nested comprehension:

L = [
    [1,2,3,        4,5,6,        7,8,9      ],
    [11,22,33,     44,55,66,     77,88,99   ],
    [111,222,333,  444,555,666,  777,888,999]
]

r = [  [ n for r in L for n in r[c:c+3] ] for c in range(0,len(L[0]),3) ]
print(r)

[[1, 2, 3,   11, 22, 33,   111, 222, 333], 
 [4, 5, 6,   44, 55, 66,   444, 555, 666], 
 [7, 8, 9,   77, 88, 99,   777, 888, 999]]
Alain T.
  • 40,517
  • 4
  • 31
  • 51
1
end_list = []
sublist_len = min(len(lst) for lst in starting_list)
for i in range(0, sublist_len, 3):
    group = []
    for lst in starting_list:
        group.append(lst[i:i+3])
    end_list.append([y for x in group for y in x])

First we start with an empty list. We calculate the length of the sublists so we don't get any out of bounds errors indexing the sublists.

We then iterate over indexes for "chunks" of these sublists. 0, 1, 2, 3, 4, 5, etc.

For each of these chunks of indexes, we create a group by appending a slice of the list to group for each sublist. At the end of that loop, we use some list comprehension logic to "flatten" the list of lists we've created, and append that list to the end_list list.

End result?

[[1, 2, 3, 11, 22, 33, 111, 222, 333], [4, 5, 6, 44, 55, 66, 444, 555, 666], [7, 8, 9, 77, 88, 99, 777, 888, 999]]

We can also use a list comprehension to accomplish this, using the same sublist_len as before. The logic is the same as before, but more direct. for i in range(0, sublist_len, 3) will yield 0, 3, and 6. We then map each of these to a list created by the nested list comprehension.

end_list = [[x for lst in starting_list for x in lst[i:i+3]] for i in range(0, sublist_len, 3)]
Chris
  • 26,361
  • 5
  • 21
  • 42