Reputation: 487
I want to write a script to take a list of categories and return the unique ways to split the categories into 2 groups. For now I have it in tuple form (list_a, list_b) where the union of list_a and list_b represents the full list of categories.
Below I have shown with an example with categories ['A','B','C','D'], I can get all the groups. However, some are duplicates (['A'], ['B', 'C', 'D']) represents the same split as (['B', 'C', 'D'], ['A']). How do I retain only unique splits? Also what is a better title for this post?
import itertools
def getCompliment(smallList, fullList):
compliment = list()
for item in fullList:
if item not in smallList:
compliment.append(item)
return compliment
optionList = ['A','B','C','D']
combos = list()
for r in range(1,len(optionList)):
tuples = list(itertools.combinations(optionList, r))
for t in tuples:
combos.append((list(t),getCompliment(list(t), optionList)))
print(combos)
[(['A'], ['B', 'C', 'D']),
(['B'], ['A', 'C', 'D']),
(['C'], ['A', 'B', 'D']),
(['D'], ['A', 'B', 'C']),
(['A', 'B'], ['C', 'D']),
(['A', 'C'], ['B', 'D']),
(['A', 'D'], ['B', 'C']),
(['B', 'C'], ['A', 'D']),
(['B', 'D'], ['A', 'C']),
(['C', 'D'], ['A', 'B']),
(['A', 'B', 'C'], ['D']),
(['A', 'B', 'D'], ['C']),
(['A', 'C', 'D'], ['B']),
(['B', 'C', 'D'], ['A'])]
I need the following:
[(['A'], ['B', 'C', 'D']),
(['B'], ['A', 'C', 'D']),
(['C'], ['A', 'B', 'D']),
(['D'], ['A', 'B', 'C']),
(['A', 'B'], ['C', 'D']),
(['A', 'C'], ['B', 'D']),
(['A', 'D'], ['B', 'C'])]
Upvotes: 3
Views: 41
Reputation: 164623
You are very close. What you need is a set
of results.
Since set
elements must be hashable and list
objects are not hashable, you can use tuple
instead. This can be achieved by some trivial changes to your code.
import itertools
def getCompliment(smallList, fullList):
compliment = list()
for item in fullList:
if item not in smallList:
compliment.append(item)
return tuple(compliment)
optionList = ('A','B','C','D')
combos = set()
for r in range(1,len(optionList)):
tuples = list(itertools.combinations(optionList, r))
for t in tuples:
combos.add(frozenset((tuple(t), getCompliment(tuple(t), optionList))))
print(combos)
{frozenset({('A',), ('B', 'C', 'D')}),
frozenset({('A', 'C', 'D'), ('B',)}),
frozenset({('A', 'B', 'D'), ('C',)}),
frozenset({('A', 'B'), ('C', 'D')}),
frozenset({('A', 'C'), ('B', 'D')}),
frozenset({('A', 'D'), ('B', 'C')}),
frozenset({('A', 'B', 'C'), ('D',)})}
If you need to convert the result back to a list of lists, this is possible via a list comprehension:
res = [list(map(list, i)) for i in combos]
[[['A'], ['B', 'C', 'D']],
[['B'], ['A', 'C', 'D']],
[['A', 'B', 'D'], ['C']],
[['A', 'B'], ['C', 'D']],
[['B', 'D'], ['A', 'C']],
[['B', 'C'], ['A', 'D']],
[['A', 'B', 'C'], ['D']]]
Upvotes: 3