Home > Net >  Copying structure of a list of list to a flat list?
Copying structure of a list of list to a flat list?

Time:11-30

I have two lists as follows.

l1=[a,b,c,d,e]
l2=[[p,q],[r,s,t]]

How do I create a list of lists from l1 similar to list l2 ?

Desired output: [[a,b],[c,d,e]]

Your help is much appreciated. Thanks!

CodePudding user response:

One possible approach: use deepcopy(l2) to create the structure of the new list, and then recursively traverse it and replace its non-list items with items taken from a copy of l1.

>>> a, b, c, d, e = "abcde"
>>> p, q, r, s, t = "pqrst"
>>> l1=[a,b,c,d,e]
>>> l2=[[p,q],[r,s,t]]
>>> from copy import deepcopy
>>> l3 = deepcopy(l2)
>>> def deep_replace(l1, l2):
...     for i, item in enumerate(l2):
...         if isinstance(item, list):
...             deep_replace(l1, item)
...         else:
...             l2[i] = l1.pop(0)
...
>>> deep_replace(l1.copy(), l3)
>>> l3
[['a', 'b'], ['c', 'd', 'e']]

This should work with arbitrarily deep lists (up to Python's recursion limit anyway).

If preserving the original l1 and l2 isn't important, you can skip the copy and deepcopy calls.

CodePudding user response:

The following approach will work for arbitrarily nested lists, and doesn't require a deep copy nor an inefficient pop from the end of the list, making this version linear on the total number of items, instead of quadratic:

def structured_replace(values, nested):
    it = iter(values)
    def _helper(nested):
        return [
            _helper(item) if isinstance(item, list) else next(it)
            for item in nested
        ]
    return _helper(nested)

a, b, c, d, e = "abcde"
p, q, r, s, t = "pqrst"
l1 = [a,b,c,d,e]
l2 = [[p,q],[r,s,t]]
print(structured_replace(l1, l2))

Also, just for fun, here's an iterative solution:

def structured_replace(values, nested):
    it = iter(values)
    top_result = []
    stack = [(nested, top_result)]
    while stack:
        item, result = stack.pop()
        if isinstance(item, list):
            subresult = []
            result.append(subresult)
            for sub in reversed(item):
                stack.append((sub, subresult))
        else:
            result.append(next(it))
    return top_result[0]

Also, here's a breadth-first approach, which we can modify the iterative approach easily and use the standard queue-based approach:

def structured_replace_breadth_first(values, nested):
    from collections import deque
    it = iter(values)
    top_result = []
    stack = deque([(nested, top_result)])
    while stack:
        item, result = stack.popleft()
        if isinstance(item, list):
            subresult = []
            result.append(subresult)
            for sub in item:
                stack.append((sub, subresult))
        else:
            result.append(next(it))
    return top_result[0]

For the differences:

In [5]: structured_replace('abcdefg', [[1, 2], 3, [4, [5, 6], 7]])
Out[5]: [['a', 'b'], 'c', ['d', ['e', 'f'], 'g']]

In [6]: structured_replace_level_first('abcdefg', [[1, 2], 3, [4, [5, 6], 7]])
Out[6]: [['b', 'c'], 'a', ['d', ['f', 'g'], 'e']]

CodePudding user response:

You can create an empty list to store the result, and a count variable to store the start index for each sub-list, then for each sublist in l2, get the size of the sublist, and take the items from list l1

res = []
count = 0
for sub in l2:
    res.append(l1[count:len(sub) count])
    count  = len(sub)
  

OUTPUT:

res
Out[79]: [['a', 'b'], ['c', 'd', 'e']]
  • Related