If I had the 1D list:
[1,2,3,4,5,6,7,8,9,10]
How would I separate the 1D list so that it would make a 2D list that has 1D elements of decreasing length, down to 1?
For example, the above list would become:
[[1,2,3,4][5,6,7][8,9][10]]
I am aware this only works with lists of certain lengths, but in this case I only need it to work for those ideal lengths.
CodePudding user response:
if no other solution is coming to your mind ,just start forming new lists from the end, it will be an O(n) solution.
CodePudding user response:
With a generator
Let's make a generator which will return the elements of a list as if they were in a flattened triangular matrix:
def tril(arr):
'''Iterate over the list as a lower triangular matrix,
e.g. if arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] then return one by one:
[1]
[2, 3]
[4, 5, 6]
[7, 8, 9, 10]
'''
N = len(arr)
left, width = 0, 1
while left < N:
yield arr[left:(right:=left width)]
left = right
width = 1
With [i for i in tril([*range(1,11)])
we get a list:
[[1], [2, 3], [4, 5, 6], [7, 8, 9, 10]]
So to get the required answer we have to apply reversing three times - to a given list arr = [*range(1,11)]
, to each item from tril(reversed(arr))
, and to the whole output list:
arr = [*range(1, 11)]
answer = [i[::-1] for i in tril(arr[::-1])][::-1]
Knowing the lenght of the first item
We can calculate the length of the first item from the equation:
n*(n 1) == 2*len(arr)
where arr
is a given list if items, and n
is the lenght of the first item of the required answer, e.g if arr = [*range(1, 11)]
then n == 4
. In other words, len(arr)
is equal to the sum of first n
natural numbers.
So we can obtain the answer this way:
arr = [*range(1, 11)]
n = round(((8*len(arr) 1)**0.5 - 1)/2)
# Usually we know the value of n
# so only the next 2 lines is needed in common case
item = iter(arr)
answer = [[next(item) for _ in range(i)] for i in range(n, 0, -1)]