Search code examples
pythonlisttuplescombinationspython-itertools

create a python list with combinations of the first element with the rest of list without repeat tuples in a combination


I'm trying to create a list of tuples in python with the combinations of first element of list with the rest elements of the list but without repeat the first element of the tuple in final result of combinations

I use this:

lst = [(2, 'ok'), (3, 'ok'), (3, 'fail'), (3, 'error'), (4, 'ok'), (4, 'fail'), (4, 'error')]

data = [[lst[0]] + list(i) for i in itertools.combinations(lst[1:], 2)]
for i in data:
    print(i)

and get this:

[(2, 'ok'), (3, 'ok'), (3, 'ok')]
[(2, 'ok'), (3, 'ok'), (3, 'fail')]
[(2, 'ok'), (3, 'ok'), (3, 'error')]
[(2, 'ok'), (3, 'ok'), (4, 'ok')]
[(2, 'ok'), (3, 'ok'), (4, 'fail')]
[(2, 'ok'), (3, 'ok'), (4, 'error')]
[(2, 'ok'), (3, 'fail'), (3, 'fail')]
[(2, 'ok'), (3, 'fail'), (3, 'error')]
[(2, 'ok'), (3, 'fail'), (4, 'ok')]
[(2, 'ok'), (3, 'fail'), (4, 'fail')]
[(2, 'ok'), (3, 'fail'), (4, 'error')]
[(2, 'ok'), (3, 'error'), (3, 'error')]
[(2, 'ok'), (3, 'error'), (4, 'ok')]
[(2, 'ok'), (3, 'error'), (4, 'fail')]
[(2, 'ok'), (3, 'error'), (4, 'error')]
[(2, 'ok'), (4, 'ok'), (4, 'ok')]
[(2, 'ok'), (4, 'ok'), (4, 'fail')]
[(2, 'ok'), (4, 'ok'), (4, 'error')]
[(2, 'ok'), (4, 'fail'), (4, 'fail')]
[(2, 'ok'), (4, 'fail'), (4, 'error')]
[(2, 'ok'), (4, 'error'), (4, 'error')]

but y want this:

[(2, 'ok'), (3, 'ok'), (4, 'ok')]
[(2, 'ok'), (3, 'ok'), (4, 'fail')]
[(2, 'ok'), (3, 'ok'), (4, 'error')]
[(2, 'ok'), (3, 'fail'), (4, 'ok')]
[(2, 'ok'), (3, 'fail'), (4, 'fail')]
[(2, 'ok'), (3, 'fail'), (4, 'error')]
[(2, 'ok'), (3, 'error'), (4, 'ok')]
[(2, 'ok'), (3, 'error'), (4, 'fail')]
[(2, 'ok'), (3, 'error'), (4, 'error')]

Thanks in advance!

PS: The len of the original lst can be > 1000

lst = [(2, 'ok'), (3, 'ok'), (3, 'fail'), (3, 'error'), .... (n, 'ok'), (n, 'fail'), (n, 'error')]

Solution

  • You could group items with the same number and later use itertool.product()

    import itertools
    
    lst = [(2, 'ok'), (3, 'ok'), (3, 'fail'), (3, 'error'), (4, 'ok'), (4, 'fail'), (4, 'error')]
    
    groups = {}
    
    for number, word in lst:
        if number not in groups:
            groups[number] = []
        groups[number].append( (number, word) )
    
    data = groups.values()
    
    for item in itertools.product(*data):
        print(item)
    

    Result:

    ((2, 'ok'), (3, 'ok'), (4, 'ok'))
    ((2, 'ok'), (3, 'ok'), (4, 'fail'))
    ((2, 'ok'), (3, 'ok'), (4, 'error'))
    ((2, 'ok'), (3, 'fail'), (4, 'ok'))
    ((2, 'ok'), (3, 'fail'), (4, 'fail'))
    ((2, 'ok'), (3, 'fail'), (4, 'error'))
    ((2, 'ok'), (3, 'error'), (4, 'ok'))
    ((2, 'ok'), (3, 'error'), (4, 'fail'))
    ((2, 'ok'), (3, 'error'), (4, 'error'))
    

    EDIT:

    You may also use itertools.groupby(lst, lambda x:x[0]) to group items.

    import itertools
    
    lst = [(2, 'ok'), (3, 'ok'), (3, 'fail'), (3, 'error'), (4, 'ok'), (4, 'fail'), (4, 'error')]
    
    groups = itertools.groupby(lst, lambda x:x[0])
    
    data = [list(val) for key, val in groups]
    #keys, data = zip(*groups)  # ???
     
    for item in itertools.product(*data):
        print(item)