Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Duplicating a list based on elements in its list of lists

I have the following list:

a = [1, 2, ['c', 'd'], 3, 4, ['e', 'f'], 5, 6]

The number of list of lists in a can vary, but the no. of elements in each list of lists will remain same.

for example, like below:

a = [1, 2, ['c', 'd'], 3, 4, ['e', 'f'], 5, 6, ['g', 'h'], 7, 8]

or

a = [1, 2, ['c', 'd', 'e'], 3, 4, ['f', 'g', 'h'], 5, 6, ['i', 'j', 'k'], 7, 8]

so for the input:

a = [1, 2, ['c', 'd'], 3, 4, ['e', 'f'], 5, 6]

I'm expecting the below output:

[[1, 2, 'c', 3, 4, 'e', 5, 6], [1, 2, 'd', 3, 4, 'f', 5, 6]]

Based on the no. of list of lists, the lists should be duplicated as shown in the above format.

And for the below input:

a = [1, 2, ['c', 'd', 'e'], 3, 4, ['f', 'g', 'h'], 5, 6, ['i', 'j', 'k'], 7, 8]

The output should be:

[[1, 2, 'c', 3, 4, 'f', 5, 6, 'i', 7, 8],
 [1, 2, 'd', 3, 4, 'g', 5, 6, 'j', 7, 8],
 [1, 2, 'e', 3, 4, 'h', 5, 6, 'k', 7, 8]]

So far, I'm able to do the following thing:

a = [1,2,['c','d'],3,4]

for i in a:
    if type(i) == list:
        t = a.index(i)
        ind = a[t]
        #idx.append(ind)
        a.remove(i)


new = []

for i in ind:
    new1 = []
    for j in a:
        new1.append(j)
    new1.insert(t,i)
    new.append(new1)

new

>> [[1, 2, 'c', 3, 4], [1, 2, 'd', 3, 4]]

How to expand the code I wrote to achieve the required task?

like image 346
sharathchandramandadi Avatar asked May 19 '18 18:05

sharathchandramandadi


1 Answers

The issue with your code is that t is a single index, you must make it a list of indices to account for multiple sublists.

Although, let me suggest alternatives...

With generators

We can transform the non-list elements to repeated generators and then use zip. This takes advantage of the fact that zip will stop iteration whenever it exhausted one of its arguments.

from itertools import repeat

def expand_list(lst):
    if not any(isinstance(el, list) for el in lst):
        return []
    else:
        return list(zip(*[x if isinstance(x, list) else repeat(x) for x in lst]))

The if-statement treats the base case when no item in your list is itself a list. An empty list is then returned. Alternatively, you could also define this case as returning only the list itself.

Example:

a = [1, 2, ['c', 'd', 'e'], 3, 4, ['f', 'g', 'h'], 5, 6, ['i', 'j', 'k'], 7, 8]
expand_list(a)
# output:
# [(1, 2, 'c', 3, 4, 'f', 5, 6, 'i', 7, 8),
#  (1, 2, 'd', 3, 4, 'g', 5, 6, 'j', 7, 8),
#  (1, 2, 'e', 3, 4, 'h', 5, 6, 'k', 7, 8)]

With exceptions

If you are not that into generators, the following solution uses list.pop to pick the next item when it encounters a list until the sublists are empty. An IndexError will indicate that we exhausted our sublists.

import copy

def expand_list(lst):
    if not any(isinstance(el, list) for el in lst):
        return []

    lst = copy.deepcopy(lst)
    output = []

    while True:
        try:
            output.append([x.pop(0) if isinstance(x, list) else x for x in lst])
        except IndexError:
            # Sublists are now empty
            break

    return output
like image 104
Olivier Melançon Avatar answered Oct 12 '22 22:10

Olivier Melançon