How to split a list into pairs in all possible ways
Take a look at itertools.combinations
.
matt@stanley:~$ python
Python 2.6.5 (r265:79063, Apr 16 2010, 13:57:41)
[GCC 4.4.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import itertools
>>> list(itertools.combinations(range(6), 2))
[(0, 1), (0, 2), (0, 3), (0, 4), (0, 5), (1, 2), (1, 3), (1, 4), (1, 5), (2, 3), (2, 4), (2, 5), (3, 4), (3, 5), (4, 5)]
I don't think there's any function in the standard library that does exactly what you need. Just using itertools.combinations
can get you a list of all possible individual pairs, but doesn't actually solve the problem of all valid pair combinations.
You could solve this easily with:
import itertools
def all_pairs(lst):
for p in itertools.permutations(lst):
i = iter(p)
yield zip(i,i)
But this will get you duplicates as it treats (a,b) and (b,a) as different, and also gives all orderings of pairs. In the end, I figured it's easier to code this from scratch than trying to filter the results, so here's the correct function.
def all_pairs(lst):
if len(lst) < 2:
yield []
return
if len(lst) % 2 == 1:
# Handle odd length list
for i in range(len(lst)):
for result in all_pairs(lst[:i] + lst[i+1:]):
yield result
else:
a = lst[0]
for i in range(1,len(lst)):
pair = (a,lst[i])
for rest in all_pairs(lst[1:i]+lst[i+1:]):
yield [pair] + rest
It's recursive, so it will run into stack issues with a long list, but otherwise does what you need.
>>> for x in all_pairs([0,1,2,3,4,5]): print x [(0, 1), (2, 3), (4, 5)] [(0, 1), (2, 4), (3, 5)] [(0, 1), (2, 5), (3, 4)] [(0, 2), (1, 3), (4, 5)] [(0, 2), (1, 4), (3, 5)] [(0, 2), (1, 5), (3, 4)] [(0, 3), (1, 2), (4, 5)] [(0, 3), (1, 4), (2, 5)] [(0, 3), (1, 5), (2, 4)] [(0, 4), (1, 2), (3, 5)] [(0, 4), (1, 3), (2, 5)] [(0, 4), (1, 5), (2, 3)] [(0, 5), (1, 2), (3, 4)] [(0, 5), (1, 3), (2, 4)] [(0, 5), (1, 4), (2, 3)]
How about this:
items = ["me", "you", "him"]
[(items[i],items[j]) for i in range(len(items)) for j in range(i+1, len(items))]
[('me', 'you'), ('me', 'him'), ('you', 'him')]
or
items = [1, 2, 3, 5, 6]
[(items[i],items[j]) for i in range(len(items)) for j in range(i+1, len(items))]
[(1, 2), (1, 3), (1, 5), (1, 6), (2, 3), (2, 5), (2, 6), (3, 5), (3, 6), (5, 6)]
Conceptually similar to @shang's answer, but it does not assume that groups are of size 2:
import itertools
def generate_groups(lst, n):
if not lst:
yield []
else:
for group in (((lst[0],) + xs) for xs in itertools.combinations(lst[1:], n-1)):
for groups in generate_groups([x for x in lst if x not in group], n):
yield [group] + groups
pprint(list(generate_groups([0, 1, 2, 3, 4, 5], 2)))
This yields:
[[(0, 1), (2, 3), (4, 5)],
[(0, 1), (2, 4), (3, 5)],
[(0, 1), (2, 5), (3, 4)],
[(0, 2), (1, 3), (4, 5)],
[(0, 2), (1, 4), (3, 5)],
[(0, 2), (1, 5), (3, 4)],
[(0, 3), (1, 2), (4, 5)],
[(0, 3), (1, 4), (2, 5)],
[(0, 3), (1, 5), (2, 4)],
[(0, 4), (1, 2), (3, 5)],
[(0, 4), (1, 3), (2, 5)],
[(0, 4), (1, 5), (2, 3)],
[(0, 5), (1, 2), (3, 4)],
[(0, 5), (1, 3), (2, 4)],
[(0, 5), (1, 4), (2, 3)]]