Get all combinations of element from a list, including all different orders & writing it in 2 different ways

Viewed 263

I have already found the question to get all possible combinations given a list, but not how to get as well all possible orders. Additionally, I am looking also for another way to output the combinations.

For example, let's say I have following list of elements:

['A', 'B', 'C']

I would like to generate a dictionary matching these 2 ways the combinations can be expressed.

The 1st one is through lists of variable length to express the different combinations and different orders:

[]
['A']
['A','B']
['B','A']
...
['A','B','C']
['A','C','B']
['C','A','B']
...

The 2nd is using fixed-size lists where positive integers indicate in reverse order the position of said element (first element starts at 0, then second element is 1, third element is 2, and so on...), and replacing 'void' element ('') with -1. This gives:

#     Initial list: [ 'A', 'B', 'C'] 
                       |    |    |
                       v    v    v
[]             ->   [ -1 , -1 , -1 ] 
['A']          ->   [  0 , -1 , -1 ]
['A','B']      ->   [  0 ,  1 , -1 ]
['B','A']      ->   [  1 ,  0 , -1 ]
...
['A','B','C']  ->   [  0 ,  1 ,  2 ]
['A','C','B']  ->   [  0 ,  2 ,  1 ]
['C','A','B']  ->   [  1 ,  2 ,  0 ]
...

Solution based on @match 's proposal

data = ['A', 'B', 'C']
result = list(chain.from_iterable([permutations(data, x) for x in range(len(data)+1)]))

numbers = []
for item in result:
    new_list = [-1, -1, -1]
    for entry in item:
        idx = data.index(entry)
        new_list[idx] = item.index(entry)
    numbers.append(new_list)

print(numbers)

[[-1, -1, -1], [0, -1, -1], [-1, 0, -1], [-1, -1, 0], [0, 1, -1], [0, -1, 1], [1, 0, -1], [-1, 0, 1], [1, -1, 0], [-1, 1, 0], [0, 1, 2], [0, 2, 1], [1, 0, 2], [2, 0, 1], [1, 2, 0], [2, 1, 0]]
2 Answers

You can use itertools.permutations to build up a list of lists containing all the combinations of the items for all the possible 'lengths' as follows (the extra list(chain.from_iterable(...)) is just there to flatten things down a level:

from itertools import chain, permutations

data = ['A', 'B', 'C']
result = list(chain.from_iterable([permutations(data, x) for x in range(len(data)+1)]))

[(), ('A',), ('B',), ('C',), ('A', 'B'), ('A', 'C'), ('B', 'A'), ('B', 'C'), ('C', 'A'), ('C', 'B'), ('A', 'B', 'C'), ('A', 'C', 'B'), ('B', 'A', 'C'), ('B', 'C', 'A'), ('C', 'A', 'B'), ('C', 'B', 'A')]

To map this onto numerical positions, you can use `data.index(string) to find its position. I'm not 100% if this is what you mean, but something like the following should get you there...

numbers = []
for item in result:
    new_list = []
    for entry in item:
        # Fill the new list with the index of each letter seen.
        new_list.append(data.index(entry))
    # Pad out the rest of the list with -1
    new_list += [-1] * (len(data) - len(new_list))
    numbers.append(new_list)

print(numbers)

[[-1, -1, -1], [0, -1, -1], [1, -1, -1], [2, -1, -1], [0, 1, -1], [0, 2, -1], [1, 0, -1], [1, 2, -1], [2, 0, -1], [2, 1, -1], [0, 1, 2], [0, 2, 1], [1, 0, 2], [1, 2, 0], [2, 0, 1], [2, 1, 0]]

How about

from itertools import combinations_with_replacement 

my_list = ['A', 'B', 'C']
combinations_with_replacement(my_list, 1)
combinations_with_replacement(my_list, 2)
combinations_with_replacement(my_list, 3)

You can then easily add the empty variant. Finally, you can then put this into a pandas data frame and replace it. If you need furhter help, just post below this post.

EDIT

I'm sorry, I have missread the question. Please find the correct solution with pandas below.

from itertools import chain, permutations
import numpy as np
import pandas as pd


my_list = ["A", "B", "C"]

my_list_permutations = list(
    chain.from_iterable(permutations(my_list, n) for n in range(len(my_list)+1)))

arr = np.full(len(my_list_permutations), -1)
df = pd.DataFrame(
    {"A": arr, "B": arr, "C": arr, "Permutation": ["" for i in range(len(arr))]})


for idx, permutation in enumerate(my_list_permutations):
    try:
        for letter in permutation:
            df.loc[idx, letter] = permutation.index(letter)

        df.loc[idx, "Permutation"] = f"{permutation}"
    except KeyError as e:
        pass
Related