Below is an algorithm to generate all pairwise combinations for a set of random variables. See here for an explanation of what constitutes a minimal all-pairs set. The algorithm below works but I feel that it is inefficient. Any suggestions would be welcome.from operator import itemgetterfrom itertools import combinations, product, zip_longest, chain, permutationsdef pairwise(*variables, **kwargs):    num_vars = len(variables)    #Organize the variable states into pairs for comparisons    indexed_vars = sorted(        ([(index, v) for v in vals] for index, vals in enumerate(variables)),        key=len,        reverse=True)    var_combos = combinations(range(num_vars), 2)    var_products = (product(indexed_vars[i], indexed_vars[j]) for i, j in var_combos)    vars = chain.from_iterable(zip_longest(*var_products))    #Initialize the builder list    builders = []    seen_pairs = set()    #Main algorithm loop    for pair in vars:        if not pair or pair in seen_pairs:            continue        d_pair = dict(pair)        #Linear search through builders to find an empty slot        #First pass: look for sets that have intersections        for builder in builders:            intersection = builder.keys() & d_pair.keys()            if len(intersection) == 1:                v = intersection.pop()                if builder[v] == d_pair[v]:                    builder.update(d_pair)                    #Update seen pairs                    seen_pairs.update(combinations(builder.items(), 2))                    break        else:            #Second Pass            for builder in builders:                intersection = builder.keys() & d_pair.keys()                if not len(intersection):                    builder.update(d_pair)                    #Update seen pairs                    seen_pairs.update(combinations(builder.items(), 2))                    break            else:                #No empty slots/pairs identified. Make a new builder                builders.append(d_pair)                seen_pairs.add(pair)    #Fill in remaining values    complete_set = set(range(num_vars))    defaults = {var[0][0]: var[0][1] for var in indexed_vars}    for builder in builders:        if len(builder) == num_vars:            yield tuple(val for index, val in sorted(builder.items()))        else:            for key in complete_set - builder.keys():                builder[key] = defaults[key]            yield tuple(val for index, val in sorted(builder.items()))Usage Example:u_vars = [    [1, 2, 3, 4],    [A, B, C],    [a, b],    ]result = list(pairwise(*u_vars))print(result) #prints list of length 12
Pairwise Combinations Generator
python;algorithm;combinatorics