Search code examples
pythoniteratorlist-comprehensionpython-itertools

Iterative type conversion over list of iterables


I have got such a list of strings:

names = ['Katia', 'Alexandre']

and I want to achieve this result:

['Katia', 'Alexandre', 'Katia Alexandre', 'Alexandre Katia']

i.e. I need all the permutations of size range(1, length(names)+1).

I wrote this function that produces a list of iterables:

import itertools

def permutations_all_sizes(iterable):
    sizes = range(1, len(iterable)+1)
    permutations = [itertools.permutations(iterable, x) for x in sizes]

    return permutations

Now, my idea was to execute a nested list comprehension to untuple the strings. However, wheter I do it nested or not nested the result is always the same:

perms = permutations_all_sizes(names)

[list(tup) for tup in perms]
[162]: [[('Catia',), ('Alexandre',)], [('Catia', 'Alexandre'), ('Alexandre', 'Catia')]]

[list(tup) for tup in [iterator for iterator in perms]]
[165]: [[('Catia',), ('Alexandre',)], [('Catia', 'Alexandre'), ('Alexandre', 'Catia')]]

Can somebody explain why such behaviour?


Solution

  • You can get the desired output with the following list comprehension:

    print([' '.join(names) for tup in perms for names in tup])
    

    Explanation of behavior of your code:

    names = ['Katia', 'Alexandre'], so

    sizes = range(1, len(iterable)+1) = range(1, 3), so

    permutations = [itertools.permutations(iterable, x) for x in sizes] =

    = [itertools.permutations(iterable, 1), itertools.permutations(iterable, 2).

    itertools.permutations(iterable, 1) contains tuples of length 1 of elements of iterable:

    names = ['Katia', 'Alexandre']
    for something in itertools.permutations(names, 1):
        print(something)  # will print ('Katia',) then ('Alexandre',)
    

    so doing list(tup) of this permutation object will give a list of tuples like [('Catia',), ('Alexandre',)].

    Same logic applies to itertools.permutations(iterable, 2):

    names = ['Katia', 'Alexandre']
    for something in itertools.permutations(names, 2):
        print(something)  # will print ('Katia', 'Alexandre'), then ('Alexandre', 'Katia')
    

    and list(tup) will give [('Katia', 'Alexandre'), ('Alexandre', 'Katia')]

    Combining them in a list comprehension [list(tup) for tup in perms] will give the output you get: [[('Catia',), ('Alexandre',)], [('Catia', 'Alexandre'), ('Alexandre', 'Catia')]]

    Modifying list comprehension to [list(tup) for tup in [iterator for iterator in perms]] does nothing: perms is already a list and [iterator for iterator in perms] is equivalent to perms.