Search code examples
pythoncombinationspython-itertoolsdictionary-comprehension

How to readably and efficeintly create a dictionary of iterable combinations with a tuple of their indices as keys?


So i have some code that works, but it is at best hard to read, and I feel inefficient as it uses two list comprehensions where a single one should suffice.

What I need is to create a dictionary of all n combinations of the letters in alpha, with the key to the dictionary for each item being a tuple of the indices in alpha for the elements in the combination. This should work for any n:

n=2

from itertools import combinations 

alpha = "abcde" 
n = 2

D = {tuple([c_i[0] for c_i in comb]): tuple([c_i[1] for c_i in comb]) 
     for comb in combinations(enumerate(alpha), n)}

>>>{(0, 1): ('a', 'b'),
 (0, 2): ('a', 'c'),
 (0, 3): ('a', 'd'),
 (0, 4): ('a', 'e'),
 (1, 2): ('b', 'c'),
 (1, 3): ('b', 'd'),
 (1, 4): ('b', 'e'),
 (2, 3): ('c', 'd'),
 (2, 4): ('c', 'e'),
 (3, 4): ('d', 'e')}

n=3

from itertools import combinations 

alpha = "abcde" 
n = 3

D = {tuple([c_i[0] for c_i in comb]): tuple([c_i[1] for c_i in comb]) 
     for comb in combinations(enumerate(alpha), n)}

>>>{(0, 1, 2): ('a', 'b', 'c'),
 (0, 1, 3): ('a', 'b', 'd'),
 (0, 1, 4): ('a', 'b', 'e'),
 (0, 2, 3): ('a', 'c', 'd'),
 (0, 2, 4): ('a', 'c', 'e'),
 (0, 3, 4): ('a', 'd', 'e'),
 (1, 2, 3): ('b', 'c', 'd'),
 (1, 2, 4): ('b', 'c', 'e'),
 (1, 3, 4): ('b', 'd', 'e'),
 (2, 3, 4): ('c', 'd', 'e')}

This is working as desired, but I want to know if there is a more readable implementation, or one where I don't need a separate comprehension for [c_i[0] for c_i in comb] and [c_i[1] for c_i in comb] as this feels inefficient.

Note: this is a minimal case representation of a more complex problem where the elements of alpha are arguments to an expensive function and I want to store the output of f(alpha[i], alpha[j], alpha[k]) in a dictionary for ease of lookup without recomputation: ans = D[(i, j, k)]


Solution

  • Try this: (I feel it's a lot less complicated than the other answer, but that one works well too)

    from itertools import combinations 
    
    alpha = "abcde" 
    n = 2
    
    print({key: tuple([alpha[i] for i in key]) for key in combinations(range(len(alpha)), n)})
    

    Output:

    {(0, 1): ('a', 'b'), (0, 2): ('a', 'c'), (0, 3): ('a', 'd'), (0, 4): ('a', 'e'), (1, 2): ('b', 'c'), (1, 3): ('b', 'd'), (1, 4): ('b', 'e'), (2, 3): ('c', 'd'), (2, 4): ('c', 'e'), (3, 4): ('d', 'e')}