6

I wonder if someone can help with the following task: What is the way to get all combinations a list can be split into sublists, when order does not matter?

Let's say I have a list of 4 items:

import itertools as it

a = [1, 2, 3, 4]
print(list(it.combinations(a, 2)))

That will give me a list of 6 possible pairs:

[(1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)]

How to make (out of it? or any other way) a set of lists that contain original [1, 2, 3, 4] sequence in any order? So for this example it will contain three sublists:

 [(1, 2), (3, 4)]
 [(1, 3), (2, 4)]
 [(1, 4), (2, 3)]

UPDATE: A small clarification: In other words, I need to get all sets of n-tuples such that their members contain all the population of original list, when the order within an n-tuple does not matter. Thus [(1, 2), (3, 4)] is ok, but [(2, 1), (3, 4)] is not needed because it is the same as the first set, if we ignore the order.

UPDATE2: So for the list of length 6, and for chunks of size 2 this fun function should work as follows:

import itertools as it
a = [1, 2, 3, 4, 5, 6,]
r = 2

# fun(a,r):
# OUT:
# [
#    (1, 2), (3, 4), (5, 6)
#    (1, 3), (2, 4), (5, 6),
#    (1, 4), (2, 3), (5, 6),
#    (1, 5), (2, 3), (4, 6),
#    (1, 6), (2, 3), (4, 5),
#  ]
3
  • Did you try print(list(it.permutations(a, 4)))? Might that be what you're looking for? Commented Aug 19, 2018 at 8:38
  • The last part of your question doesn't agree with your desired output. You say "...that contain original [1, 2, 3, 4] sequence in any order?" For that you would simply reshuffle using something like random.shuffle. What your output is telling me is that you want to randomly pick pairs from list(it.combinations(a, 2)). Could you clarify a bit? Commented Aug 19, 2018 at 9:23
  • 1
    @JosephWood: Sure, let me clarify a bit: I need to get all sets of n-tuples such that their members contain all the population of original list, when the order within an n-tuple does not matter. Thus [(1, 2), (3, 4)] is ok, but [(2, 1), (3, 4)] is not needed because it is the same as the first set, if we ignore the order Commented Aug 19, 2018 at 9:51

3 Answers 3

2

Just zip the combinations, with its reverse and take only the first half of the resulting list

>>> import itertools as it
>>> lst = [1, 2, 3, 4]
>>> r = len(lst)//2
>>> combs = list(it.combinations(lst, r))
>>> list(it.islice(zip(combs, reversed(combs)), len(combs)//2))
[((1, 2), (3, 4)), ((1, 3), (2, 4)), ((1, 4), (2, 3))]
Sign up to request clarification or add additional context in comments.

4 Comments

This solution works for this specific list length. For lst = list(range(1,7)) it splits it into subgroups of 3: [((1, 2, 3), (4, 5, 6)), ((1, 2, 4), (3, 5, 6)), ((1, 2, 5), (3, 4, 6)), ((1, 2, 6), (3, 4, 5)), ((1, 3, 4), (2, 5, 6)), ((1, 3, 5), (2, 4, 6)), ((1, 3, 6), (2, 4, 5)), ((1, 4, 5), (2, 3, 6)), ((1, 4, 6), (2, 3, 5)), ((1, 5, 6), (2, 3, 4))]
and with lst = list(range(1,7)) and r = 2 it produces the wrong result: [((1, 2), (5, 6)), ((1, 3), (4, 6)), ((1, 4), (4, 5)), ((1, 5), (3, 6)), ((1, 6), (3, 5)), ((2, 3), (3, 4)), ((2, 4), (2, 6))]
It works only when r is len(lst)/2. Can you give an example output you expect when r=2 for a list for length 7
Just added an example in UPDATE2 in the main text
0

As you require the "remainder" of what is in a, you can use a set difference

In [901]: [(c, tuple(set(a) - set(c))) for c in it.combinations(a, 2)]
Out[901]:
[((1, 2), (3, 4)),
 ((1, 3), (2, 4)),
 ((1, 4), (2, 3)),
 ((2, 3), (1, 4)),
 ((2, 4), (1, 3)),
 ((3, 4), (1, 2))]

However, this gives you twice as many results as you require so to eliminate these duplicates we need to sort and setify the result set which will give us a set of lists which can't be turned into sets. You should then cast the lists to tuples.

In [900]: {tuple(sorted((c, tuple(set(a) - set(c))))) for c in it.combinations(a, 2)}
Out[900]: {((1, 2), (3, 4)), ((1, 3), (2, 4)), ((1, 4), (2, 3))}

If you require a list of list of tuple then you can use the following

In [902]: s = {tuple(sorted((c, tuple(set_a - set(c))))) for c in it.combinations(a, 2)}

In [903]: [list(l) for l in s]
Out[903]: [[(1, 3), (2, 4)], [(1, 4), (2, 3)], [(1, 2), (3, 4)]]

Comments

0
a = [1, 2, 3, 4]
choices = []
for i in range(len(a)):
  for j in range(i+1, len(a)):
      sub_a1 = (a[i], a[j])
      sub_a2 = tuple(j for j in a if j not in sub_a1)
      sub_a = sorted([sub_a1, sub_a2])
      if sub_a not in choices:
         choices.append(sub_a)
for k in choices:
  print(k)

May be this code can help your requirements.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.