Search code examples
pythonlistlist-comprehension

Copying structure of a list of list to a flat list?


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!


Solution

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