Creating several lists where each has all items from original list in unique pairs

67 views Asked by At

I am trying to randomly pair two items from a list together in as many combinations as possible, then separate these into multiple lists where each item is included on each list and each pair is included exactly once in all the lists combined.

So for example if the following items were on the original list: banana apple peach pear

I would want to produce the following as separate lists:

banana apple
peach pear

banana peach
apple pear

banana pear
apple peach

I added a list of 12 fruits then found every combination of pairs from the list using itertools. I made several new empty lists and created a for loop to check if either item in the pair has already been used in each list, and if it has to assign it to a new list:

fruitcombos = list(it.combinations(fruits, 2))

s1 = []
s2 = []
...
s10 = []

for group in fruitcombos:
    if not any(group[0] in x for x in s1) and not any(group[1] in x for x in s1):
            s1.append(group)
    elif not any(group[0] in x for x in s2) and not any(group[1] in x for x in s2):
            s2.append(group)
    elif not any(group[0] in x for x in s3) and not any(group[1] in x for x in s3):
            s3.append(group)
    ...
    
    elif not any(group[0] in x for x in s10) and not any(group[1] in x for x in s10):
            s10.append(group)

I've looked at the itertools module and tried round_robin, ncycles, sliding_window, and others but cannot figure out how to solve this problem in a more elegant way. It also isn't working properly - with the loop I've tried, the first list (s1) has 12 of the 12 items as expected. However other lists decrease in number, with the fourth list onwards only including 8 of the 12 items because parts of the other pairs have already been included in other lists. How would I avoid this?

I would greatly appreciate any help.

2

There are 2 answers

2
Reilas On

Here is an example; I may have over-looked the reins.

Utilize the itertools.permutations function, applying each to a dictionary.

import itertools as i
l = ['banana', 'apple', 'peach', 'pear']
p = {(a, b): [c, d] for a, b, c, d in i.permutations(l, 4)}

Output

{('banana', 'apple'): ['pear', 'peach'],
 ('banana', 'peach'): ['pear', 'apple'],
 ('banana', 'pear'): ['peach', 'apple'],
 ('apple', 'banana'): ['pear', 'peach'],
 ('apple', 'peach'): ['pear', 'banana'],
 ('apple', 'pear'): ['peach', 'banana'],
 ('peach', 'banana'): ['pear', 'apple'],
 ('peach', 'apple'): ['pear', 'banana'],
 ('peach', 'pear'): ['apple', 'banana'],
 ('pear', 'banana'): ['peach', 'apple'],
 ('pear', 'apple'): ['peach', 'banana'],
 ('pear', 'peach'): ['apple', 'banana']}

Edit

"... I am trying to assign each item from the input list to a unique pair in each output list. So each item will be included exactly once in each output list, and each pair in an output list will not be repeated in the other output lists. ...

... my list has 40 items and increasing the list size does not yield unique pairs, do you know how this could be done?"

Similarly, start by generating all combinations of pairs.
We'll limit the factor, by qualifying the iteration; in this case to, "banana".

From here, traverse each pair, generating a filtered list.

import itertools as i
l = ['banana', 'apple', 'peach', 'pear']
p = [(a, b) for a, b in i.combinations(l, 2) if a == l[0]]
d = {}
for k in p:
    v = zip(*[filter(lambda x: x not in k, l)] * 2)
    d.update({k: list(v)})

Output

{('banana', 'apple'): [('peach', 'pear')],
 ('banana', 'peach'): [('apple', 'pear')],
 ('banana', 'pear'): [('apple', 'peach')]}

Here is an output, for a though z.

{('a', 'b'): [('c', 'd'), ('e', 'f'), ('g', 'h'), ('i', 'j'), ('k', 'l'), ('m', 'n'), ('o', 'p'), ('q', 'r'), ('s', 't'), ('u', 'v'), ('w', 'x'), ('y', 'z')],
 ('a', 'c'): [('b', 'd'), ('e', 'f'), ('g', 'h'), ('i', 'j'), ('k', 'l'), ('m', 'n'), ('o', 'p'), ('q', 'r'), ('s', 't'), ('u', 'v'), ('w', 'x'), ('y', 'z')],
 ('a', 'd'): [('b', 'c'), ('e', 'f'), ('g', 'h'), ('i', 'j'), ('k', 'l'), ('m', 'n'), ('o', 'p'), ('q', 'r'), ('s', 't'), ('u', 'v'), ('w', 'x'), ('y', 'z')],
 ('a', 'e'): [('b', 'c'), ('d', 'f'), ('g', 'h'), ('i', 'j'), ('k', 'l'), ('m', 'n'), ('o', 'p'), ('q', 'r'), ('s', 't'), ('u', 'v'), ('w', 'x'), ('y', 'z')],
 ('a', 'f'): [('b', 'c'), ('d', 'e'), ('g', 'h'), ('i', 'j'), ('k', 'l'), ('m', 'n'), ('o', 'p'), ('q', 'r'), ('s', 't'), ('u', 'v'), ('w', 'x'), ('y', 'z')],
 ('a', 'g'): [('b', 'c'), ('d', 'e'), ('f', 'h'), ('i', 'j'), ('k', 'l'), ('m', 'n'), ('o', 'p'), ('q', 'r'), ('s', 't'), ('u', 'v'), ('w', 'x'), ('y', 'z')],
 ('a', 'h'): [('b', 'c'), ('d', 'e'), ('f', 'g'), ('i', 'j'), ('k', 'l'), ('m', 'n'), ('o', 'p'), ('q', 'r'), ('s', 't'), ('u', 'v'), ('w', 'x'), ('y', 'z')],
 ('a', 'i'): [('b', 'c'), ('d', 'e'), ('f', 'g'), ('h', 'j'), ('k', 'l'), ('m', 'n'), ('o', 'p'), ('q', 'r'), ('s', 't'), ('u', 'v'), ('w', 'x'), ('y', 'z')],
 ('a', 'j'): [('b', 'c'), ('d', 'e'), ('f', 'g'), ('h', 'i'), ('k', 'l'), ('m', 'n'), ('o', 'p'), ('q', 'r'), ('s', 't'), ('u', 'v'), ('w', 'x'), ('y', 'z')],
 ('a', 'k'): [('b', 'c'), ('d', 'e'), ('f', 'g'), ('h', 'i'), ('j', 'l'), ('m', 'n'), ('o', 'p'), ('q', 'r'), ('s', 't'), ('u', 'v'), ('w', 'x'), ('y', 'z')],
 ('a', 'l'): [('b', 'c'), ('d', 'e'), ('f', 'g'), ('h', 'i'), ('j', 'k'), ('m', 'n'), ('o', 'p'), ('q', 'r'), ('s', 't'), ('u', 'v'), ('w', 'x'), ('y', 'z')],
 ('a', 'm'): [('b', 'c'), ('d', 'e'), ('f', 'g'), ('h', 'i'), ('j', 'k'), ('l', 'n'), ('o', 'p'), ('q', 'r'), ('s', 't'), ('u', 'v'), ('w', 'x'), ('y', 'z')],
 ('a', 'n'): [('b', 'c'), ('d', 'e'), ('f', 'g'), ('h', 'i'), ('j', 'k'), ('l', 'm'), ('o', 'p'), ('q', 'r'), ('s', 't'), ('u', 'v'), ('w', 'x'), ('y', 'z')],
 ('a', 'o'): [('b', 'c'), ('d', 'e'), ('f', 'g'), ('h', 'i'), ('j', 'k'), ('l', 'm'), ('n', 'p'), ('q', 'r'), ('s', 't'), ('u', 'v'), ('w', 'x'), ('y', 'z')],
 ('a', 'p'): [('b', 'c'), ('d', 'e'), ('f', 'g'), ('h', 'i'), ('j', 'k'), ('l', 'm'), ('n', 'o'), ('q', 'r'), ('s', 't'), ('u', 'v'), ('w', 'x'), ('y', 'z')],
 ('a', 'q'): [('b', 'c'), ('d', 'e'), ('f', 'g'), ('h', 'i'), ('j', 'k'), ('l', 'm'), ('n', 'o'), ('p', 'r'), ('s', 't'), ('u', 'v'), ('w', 'x'), ('y', 'z')],
 ('a', 'r'): [('b', 'c'), ('d', 'e'), ('f', 'g'), ('h', 'i'), ('j', 'k'), ('l', 'm'), ('n', 'o'), ('p', 'q'), ('s', 't'), ('u', 'v'), ('w', 'x'), ('y', 'z')],
 ('a', 's'): [('b', 'c'), ('d', 'e'), ('f', 'g'), ('h', 'i'), ('j', 'k'), ('l', 'm'), ('n', 'o'), ('p', 'q'), ('r', 't'), ('u', 'v'), ('w', 'x'), ('y', 'z')],
 ('a', 't'): [('b', 'c'), ('d', 'e'), ('f', 'g'), ('h', 'i'), ('j', 'k'), ('l', 'm'), ('n', 'o'), ('p', 'q'), ('r', 's'), ('u', 'v'), ('w', 'x'), ('y', 'z')],
 ('a', 'u'): [('b', 'c'), ('d', 'e'), ('f', 'g'), ('h', 'i'), ('j', 'k'), ('l', 'm'), ('n', 'o'), ('p', 'q'), ('r', 's'), ('t', 'v'), ('w', 'x'), ('y', 'z')],
 ('a', 'v'): [('b', 'c'), ('d', 'e'), ('f', 'g'), ('h', 'i'), ('j', 'k'), ('l', 'm'), ('n', 'o'), ('p', 'q'), ('r', 's'), ('t', 'u'), ('w', 'x'), ('y', 'z')],
 ('a', 'w'): [('b', 'c'), ('d', 'e'), ('f', 'g'), ('h', 'i'), ('j', 'k'), ('l', 'm'), ('n', 'o'), ('p', 'q'), ('r', 's'), ('t', 'u'), ('v', 'x'), ('y', 'z')],
 ('a', 'x'): [('b', 'c'), ('d', 'e'), ('f', 'g'), ('h', 'i'), ('j', 'k'), ('l', 'm'), ('n', 'o'), ('p', 'q'), ('r', 's'), ('t', 'u'), ('v', 'w'), ('y', 'z')],
 ('a', 'y'): [('b', 'c'), ('d', 'e'), ('f', 'g'), ('h', 'i'), ('j', 'k'), ('l', 'm'), ('n', 'o'), ('p', 'q'), ('r', 's'), ('t', 'u'), ('v', 'w'), ('x', 'z')],
 ('a', 'z'): [('b', 'c'), ('d', 'e'), ('f', 'g'), ('h', 'i'), ('j', 'k'), ('l', 'm'), ('n', 'o'), ('p', 'q'), ('r', 's'), ('t', 'u'), ('v', 'w'), ('x', 'y')]}
1
inspectorG4dget On
In [4]: def partitions(L, k):
   ...:     combos = list(itertools.combinations(L, k))
   ...:     m = len(combos)//2
   ...:     return [c1+c2 for c1,c2 in zip(combos[:m], combos[m:][::-1])]
   ...:

In [5]: partitions('banana apple peach pear'.split(), 2)
Out[5]:
[('banana', 'apple', 'peach', 'pear'),
 ('banana', 'peach', 'apple', 'pear'),
 ('banana', 'pear', 'apple', 'peach')]

Or, alternatively

In [6]: def partitions(L, k):
   ...:     combos = list(itertools.combinations(L, k))
   ...:     m = len(combos)//2
   ...:     return list(zip(combos[:m], combos[m:][::-1]))
   ...:

In [7]: partitions('banana apple peach pear'.split(), 2)
Out[7]:
[(('banana', 'apple'), ('peach', 'pear')),
 (('banana', 'peach'), ('apple', 'pear')),
 (('banana', 'pear'), ('apple', 'peach'))]