Unique combinations of a list of tuplesPicking unordered combinations from pools with overlapHow do I check if a list is empty?Finding the index of an item given a list containing it in PythonWhat is the difference between Python's list methods append and extend?What's the difference between lists and tuples?How to make a flat list out of list of listsHow do I concatenate two lists in Python?How to clone or copy a list?What are “named tuples” in Python?How to sort (list/tuple) of lists/tuples by the element at a given index?How do I list all files of a directory?
Which note goes on which side of the stem?
Slitherlink Fillomino hybrid
How would one country purchase another?
Mathematical uses of string theory
Why did this happen to Thanos's ships at the end of "Avengers: Endgame"?
In an emergency, how do I find and share my position?
Compelling story with the world as a villain
I have a player who yells
Why isn't "I've" a proper response?
Can realistic planetary invasion have any meaningful strategy?
How to use "Du hast/ Du hattest'?
Justifying the use of directed energy weapons
Are modern clipless shoes and pedals that much better than toe clips and straps?
Using `With[...]` with a list specification as a variable
Efficiently pathfinding many flocking enemies around obstacles
If the first law of thermodynamics ensures conservation of energy, why does it allow systems to lose energy?
What does どうかと思う mean?
Is “I am getting married with my sister” ambiguous?
Checking a beta regression model via glmmTMB with DHARMa package
Why in most German places is the church the tallest building?
Would this system work to purify water?
I got kicked out from graduate school in the past. How do I include this on my CV?
What is the hex versus octal timeline?
Why were movies shot on film shot at 24 frames per second?
Unique combinations of a list of tuples
Picking unordered combinations from pools with overlapHow do I check if a list is empty?Finding the index of an item given a list containing it in PythonWhat is the difference between Python's list methods append and extend?What's the difference between lists and tuples?How to make a flat list out of list of listsHow do I concatenate two lists in Python?How to clone or copy a list?What are “named tuples” in Python?How to sort (list/tuple) of lists/tuples by the element at a given index?How do I list all files of a directory?
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty margin-bottom:0;
Given a list of 3-tuples, for example:[(1,2,3), (4,5,6), (7,8,9)]
how would you compute all possible combinations and combinations of subsets?
In this case the result should look like this:
[
(1), (1,4), (1,5), (1,6), (1,7), (1,8), (1,9), (1,4,7), (1,4,8), (1,4,9), (1,5,7), (1,5,8), (1,5,9), (1,6,7), (1,6,8), (1,6,9),
(2), ...,
(3), ...,
(4), (4,7), (4,8), (4,9),
(5), (5,7), (5,8), (5,9),
(6), (6,7), (6,8), (6,9),
(7), (8), (9)
]
- all tuples with identical elements are regarded the same
- combinations which derive from the same tuples are not allowed (e.g. these shouldn't be in the solution:
(1,2)
,(4,6)
or(7,8,9)
)
python tuples combinations permutation
add a comment |
Given a list of 3-tuples, for example:[(1,2,3), (4,5,6), (7,8,9)]
how would you compute all possible combinations and combinations of subsets?
In this case the result should look like this:
[
(1), (1,4), (1,5), (1,6), (1,7), (1,8), (1,9), (1,4,7), (1,4,8), (1,4,9), (1,5,7), (1,5,8), (1,5,9), (1,6,7), (1,6,8), (1,6,9),
(2), ...,
(3), ...,
(4), (4,7), (4,8), (4,9),
(5), (5,7), (5,8), (5,9),
(6), (6,7), (6,8), (6,9),
(7), (8), (9)
]
- all tuples with identical elements are regarded the same
- combinations which derive from the same tuples are not allowed (e.g. these shouldn't be in the solution:
(1,2)
,(4,6)
or(7,8,9)
)
python tuples combinations permutation
But wait, why(1)
to(9)
are part of the soultion if(1,2)
is not allowed given the second rule ?
– Drey
Aug 10 at 19:26
It looks like there are three sets of tuples: 1)[(x,) for x in the_list[0]]
, 2)[(x,y) for x in the_list[0] for y in the_list[1]]
, and 3)[(x,y,z) for x in the_list[0] for y in the_list[1] for z in the_list[2]]
.
– chepner
Aug 10 at 19:50
Possible duplicate of Picking unordered combinations from pools with overlap
– Joseph Wood
Aug 10 at 19:52
add a comment |
Given a list of 3-tuples, for example:[(1,2,3), (4,5,6), (7,8,9)]
how would you compute all possible combinations and combinations of subsets?
In this case the result should look like this:
[
(1), (1,4), (1,5), (1,6), (1,7), (1,8), (1,9), (1,4,7), (1,4,8), (1,4,9), (1,5,7), (1,5,8), (1,5,9), (1,6,7), (1,6,8), (1,6,9),
(2), ...,
(3), ...,
(4), (4,7), (4,8), (4,9),
(5), (5,7), (5,8), (5,9),
(6), (6,7), (6,8), (6,9),
(7), (8), (9)
]
- all tuples with identical elements are regarded the same
- combinations which derive from the same tuples are not allowed (e.g. these shouldn't be in the solution:
(1,2)
,(4,6)
or(7,8,9)
)
python tuples combinations permutation
Given a list of 3-tuples, for example:[(1,2,3), (4,5,6), (7,8,9)]
how would you compute all possible combinations and combinations of subsets?
In this case the result should look like this:
[
(1), (1,4), (1,5), (1,6), (1,7), (1,8), (1,9), (1,4,7), (1,4,8), (1,4,9), (1,5,7), (1,5,8), (1,5,9), (1,6,7), (1,6,8), (1,6,9),
(2), ...,
(3), ...,
(4), (4,7), (4,8), (4,9),
(5), (5,7), (5,8), (5,9),
(6), (6,7), (6,8), (6,9),
(7), (8), (9)
]
- all tuples with identical elements are regarded the same
- combinations which derive from the same tuples are not allowed (e.g. these shouldn't be in the solution:
(1,2)
,(4,6)
or(7,8,9)
)
python tuples combinations permutation
python tuples combinations permutation
edited Aug 11 at 8:39
Gilad Green
31.3k5 gold badges35 silver badges60 bronze badges
31.3k5 gold badges35 silver badges60 bronze badges
asked Aug 10 at 18:22
p4rchp4rch
837 bronze badges
837 bronze badges
But wait, why(1)
to(9)
are part of the soultion if(1,2)
is not allowed given the second rule ?
– Drey
Aug 10 at 19:26
It looks like there are three sets of tuples: 1)[(x,) for x in the_list[0]]
, 2)[(x,y) for x in the_list[0] for y in the_list[1]]
, and 3)[(x,y,z) for x in the_list[0] for y in the_list[1] for z in the_list[2]]
.
– chepner
Aug 10 at 19:50
Possible duplicate of Picking unordered combinations from pools with overlap
– Joseph Wood
Aug 10 at 19:52
add a comment |
But wait, why(1)
to(9)
are part of the soultion if(1,2)
is not allowed given the second rule ?
– Drey
Aug 10 at 19:26
It looks like there are three sets of tuples: 1)[(x,) for x in the_list[0]]
, 2)[(x,y) for x in the_list[0] for y in the_list[1]]
, and 3)[(x,y,z) for x in the_list[0] for y in the_list[1] for z in the_list[2]]
.
– chepner
Aug 10 at 19:50
Possible duplicate of Picking unordered combinations from pools with overlap
– Joseph Wood
Aug 10 at 19:52
But wait, why
(1)
to (9)
are part of the soultion if (1,2)
is not allowed given the second rule ?– Drey
Aug 10 at 19:26
But wait, why
(1)
to (9)
are part of the soultion if (1,2)
is not allowed given the second rule ?– Drey
Aug 10 at 19:26
It looks like there are three sets of tuples: 1)
[(x,) for x in the_list[0]]
, 2) [(x,y) for x in the_list[0] for y in the_list[1]]
, and 3) [(x,y,z) for x in the_list[0] for y in the_list[1] for z in the_list[2]]
.– chepner
Aug 10 at 19:50
It looks like there are three sets of tuples: 1)
[(x,) for x in the_list[0]]
, 2) [(x,y) for x in the_list[0] for y in the_list[1]]
, and 3) [(x,y,z) for x in the_list[0] for y in the_list[1] for z in the_list[2]]
.– chepner
Aug 10 at 19:50
Possible duplicate of Picking unordered combinations from pools with overlap
– Joseph Wood
Aug 10 at 19:52
Possible duplicate of Picking unordered combinations from pools with overlap
– Joseph Wood
Aug 10 at 19:52
add a comment |
5 Answers
5
active
oldest
votes
You can use recursion with a generator:
data = [(1,2,3), (4,5,6), (7,8,9)]
def combos(d, c = []):
if len(c) == len(d):
yield c
else:
for i in d:
if i not in c:
yield from combos(d, c+[i])
def product(d, c = []):
if c:
yield tuple(c)
if d:
for i in d[0]:
yield from product(d[1:], c+[i])
result = sorted(i for b in combos(data) for i in product(b))
final_result = [a for i, a in enumerate(result) if all(len(c) != len(a) or len(set(c)&set(a)) != len(a) for c in result[:i])]
Output:
[(1,), (1, 4), (1, 4, 7), (1, 4, 8), (1, 4, 9), (1, 5), (1, 5, 7), (1, 5, 8), (1, 5, 9), (1, 6), (1, 6, 7), (1, 6, 8), (1, 6, 9), (1, 7), (1, 8), (1, 9), (2,), (2, 4), (2, 4, 7), (2, 4, 8), (2, 4, 9), (2, 5), (2, 5, 7), (2, 5, 8), (2, 5, 9), (2, 6), (2, 6, 7), (2, 6, 8), (2, 6, 9), (2, 7), (2, 8), (2, 9), (3,), (3, 4), (3, 4, 7), (3, 4, 8), (3, 4, 9), (3, 5), (3, 5, 7), (3, 5, 8), (3, 5, 9), (3, 6), (3, 6, 7), (3, 6, 8), (3, 6, 9), (3, 7), (3, 8), (3, 9), (4,), (4, 7), (4, 8), (4, 9), (5,), (5, 7), (5, 8), (5, 9), (6,), (6, 7), (6, 8), (6, 9), (7,), (8,), (9,)]
add a comment |
Here is a non-recursive solution with a simple for
loop. Uniqueness is enforced by applying set
to the list of the outputted tuples.
lsts = [(1,2,3), (4,5,6), (7,8,9)]
res = [[]]
for lst in lsts:
res += [(*r, x) for r in res for x in lst]
# print(tuple(lst) for lst in res[1:])
# (5, 9), (4, 7), (6, 9), (1, 4, 7), (2, 6, 9), (4, 8), (3, 4, 7), (2,
# 8), (2, 6, 8), (9,), (2, 5, 8), (1, 6), (3, 6, 8), (2, 5, 9), (3, 5,
# 9), (3, 7), (2, 5), (3, 6, 9), (5, 8), (1, 6, 8), (3, 5, 8), (2, 6,
# 7), (4, 9), (6, 7), (1,), (2, 9), (1, 6, 9), (3,), (1, 5), (5,), (3,
# 6), (7,), (3, 6, 7), (1, 5, 9), (2, 6), (2, 4, 7), (1, 5, 8), (3, 4,
# 8), (8,), (3, 4, 9), (1, 4), (1, 6, 7), (3, 9), (1, 9), (2, 5, 7), (3,
# 5), (2, 7), (2, 4, 9), (6, 8), (1, 5, 7), (2,), (2, 4, 8), (5, 7), (1,
# 4, 8), (3, 5, 7), (4,), (3, 8), (1, 8), (1, 4, 9), (6,), (1, 7), (3,
# 4), (2, 4)
Great solution! Only three lines of pure Python code, no imports necessary, by far the fastest solution and currently the only one that also includes the empty set (which should be part of the solution, IMHO).
– wovano
Aug 11 at 10:05
BTW: You mention that uniqueness is enforced by applyingset
, but I think the list is already correct (i.e. contains only unique values, no duplicates).
– wovano
Aug 11 at 10:06
1
Thanks. There may be duplicates for other input values, like[(1,2,3), (1,2,4), (1,2,5)]
. I also dropped the empty list (res[0]
) before passing to set by analogy to the original example, but I agree that the rules are unclear on this.
– hilberts_drinking_problem
Aug 11 at 16:22
add a comment |
Using itertools:
import itertools as it
def all_combinations(groups):
result = set()
for prod in it.product(*groups):
for length in range(1, len(groups) + 1):
result.update(it.combinations(prod, length))
return result
all_combinations([(1,2,3), (4,5,6), (7,8,9)])
add a comment |
Another version:
from itertools import product, combinations
lst = [(1,2,3), (4,5,6), (7,8,9)]
def generate(lst):
for idx in range(len(lst)):
for val in lst[idx]:
yield (val,)
for j in range(1, len(lst)):
for c in combinations(lst[idx+1:], j):
yield from tuple((val,) + i for i in product(*c))
l = [*generate(lst)]
print(l)
Prints:
[(1,), (1, 4), (1, 5), (1, 6), (1, 7), (1, 8), (1, 9), (1, 4, 7), (1, 4, 8), (1, 4, 9), (1, 5, 7), (1, 5, 8), (1, 5, 9), (1, 6, 7), (1, 6, 8), (1, 6, 9), (2,), (2, 4), (2, 5), (2, 6), (2, 7), (2, 8), (2, 9), (2, 4, 7), (2, 4, 8), (2, 4, 9), (2, 5, 7), (2, 5, 8), (2, 5, 9), (2, 6, 7), (2, 6, 8), (2, 6, 9), (3,), (3, 4), (3, 5), (3, 6), (3, 7), (3, 8), (3, 9), (3, 4, 7), (3, 4, 8), (3, 4, 9), (3, 5, 7), (3, 5, 8), (3, 5, 9), (3, 6, 7), (3, 6, 8), (3, 6, 9), (4,), (4, 7), (4, 8), (4, 9), (5,), (5, 7), (5, 8), (5, 9), (6,), (6, 7), (6, 8), (6, 9), (7,), (8,), (9,)]
add a comment |
Thank to @wovano for clarifying rule 2. This makes the solution even more shorter:
from itertools import chain, combinations, product
blubb = [(1, 2, 3), (4, 5, 6), (7, 8, 9)]
set_combos = chain.from_iterable(combinations(blubb, i) for i in range(len(blubb) + 1))
result_func = list(chain.from_iterable(map(lambda x: product(*x), set_combos)))
And as a bonus a speed comparison. @hilberts_drinking_problem's solution is awesome but there is an overhead.
def pure_python(list_of_tuples):
res = [tuple()]
for lst in list_of_tuples:
res += [(*r, x) for r in res for x in lst]
return res
def with_itertools(list_of_tuples):
set_combos = chain.from_iterable(combinations(list_of_tuples, i) for i in range(len(list_of_tuples) + 1))
return list(chain.from_iterable(map(lambda x: product(*x), set_combos)))
assert sorted(with_itertools(blubb), key=str) == sorted(pure_python(blubb), key=str)
Both computes the same stuff, but...
%timeit with_itertools(blubb)
7.18 µs ± 11.3 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
%timeit pure_python(blubb)
10.5 µs ± 46 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
although for small samples itertools
are little bit faster there is a large gap when the set grows:
import toolz
large_blubb = list(toolz.partition_all(3, range(3*10)))
assert sorted(with_itertools(large_blubb), key=str) == sorted(pure_python(large_blubb), key=str)
%timeit with_itertools(large_blubb)
106 ms ± 307 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
%timeit pure_python(large_blubb)
262 ms ± 1.85 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
which makes itertools
's solution 2,5 times faster.
Edit: corrected according to rule 2. Plus speed comparison
Edit: fix yet another mistake - now the speed comparison is realistic
It seems you didn't understand the problem completely. Double-check the last requirement: "combinations which derive from the same tuples are not allowed". So it means you should use 0 or 1 element from(1,2,3)
plus 0 or 1 element from(4,5,6)
and 0 or 1 element from(7,8,9)
. See the output of the other answers as reference. Your solution returns invalid combinations such as(1,2,4)
as well.
– wovano
Aug 11 at 9:56
Thank you @wovano for the explanation! I edited the answer. Now it should run according to the rules.
– Drey
Aug 11 at 12:31
Nice improvement!! I would change the 3th line toset_combos = chain.from_iterable(combinations(blubb, i) for i in range(len(blubb) + 1))
, so that it works for arbitrary input length instead of fixed length of 3. It'll also add the empty list, so you don't have to add it manually (e.g. remove[[]] +
) on the next line. You're right that your solution is much faster for large input sets. Well done :-)
– wovano
Aug 11 at 13:31
Thanks for the suggestions. Instead oflen(blubb)+1
I usedlen(blubb[0])+1
if I understand correctly.
– Drey
Aug 11 at 14:39
No, it really must belen(blubb)
and notlen(blubb[0])
, because you are creating combinations of sets (sets of numbers, not Pythonset
s), so you have to specify the number of sets, which islen(blubb)
. NB: Why the name blubb?? A more descriptive name might be helpful ;-)
– wovano
Aug 11 at 15:22
|
show 1 more comment
Your Answer
StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f57444657%2funique-combinations-of-a-list-of-tuples%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
5 Answers
5
active
oldest
votes
5 Answers
5
active
oldest
votes
active
oldest
votes
active
oldest
votes
You can use recursion with a generator:
data = [(1,2,3), (4,5,6), (7,8,9)]
def combos(d, c = []):
if len(c) == len(d):
yield c
else:
for i in d:
if i not in c:
yield from combos(d, c+[i])
def product(d, c = []):
if c:
yield tuple(c)
if d:
for i in d[0]:
yield from product(d[1:], c+[i])
result = sorted(i for b in combos(data) for i in product(b))
final_result = [a for i, a in enumerate(result) if all(len(c) != len(a) or len(set(c)&set(a)) != len(a) for c in result[:i])]
Output:
[(1,), (1, 4), (1, 4, 7), (1, 4, 8), (1, 4, 9), (1, 5), (1, 5, 7), (1, 5, 8), (1, 5, 9), (1, 6), (1, 6, 7), (1, 6, 8), (1, 6, 9), (1, 7), (1, 8), (1, 9), (2,), (2, 4), (2, 4, 7), (2, 4, 8), (2, 4, 9), (2, 5), (2, 5, 7), (2, 5, 8), (2, 5, 9), (2, 6), (2, 6, 7), (2, 6, 8), (2, 6, 9), (2, 7), (2, 8), (2, 9), (3,), (3, 4), (3, 4, 7), (3, 4, 8), (3, 4, 9), (3, 5), (3, 5, 7), (3, 5, 8), (3, 5, 9), (3, 6), (3, 6, 7), (3, 6, 8), (3, 6, 9), (3, 7), (3, 8), (3, 9), (4,), (4, 7), (4, 8), (4, 9), (5,), (5, 7), (5, 8), (5, 9), (6,), (6, 7), (6, 8), (6, 9), (7,), (8,), (9,)]
add a comment |
You can use recursion with a generator:
data = [(1,2,3), (4,5,6), (7,8,9)]
def combos(d, c = []):
if len(c) == len(d):
yield c
else:
for i in d:
if i not in c:
yield from combos(d, c+[i])
def product(d, c = []):
if c:
yield tuple(c)
if d:
for i in d[0]:
yield from product(d[1:], c+[i])
result = sorted(i for b in combos(data) for i in product(b))
final_result = [a for i, a in enumerate(result) if all(len(c) != len(a) or len(set(c)&set(a)) != len(a) for c in result[:i])]
Output:
[(1,), (1, 4), (1, 4, 7), (1, 4, 8), (1, 4, 9), (1, 5), (1, 5, 7), (1, 5, 8), (1, 5, 9), (1, 6), (1, 6, 7), (1, 6, 8), (1, 6, 9), (1, 7), (1, 8), (1, 9), (2,), (2, 4), (2, 4, 7), (2, 4, 8), (2, 4, 9), (2, 5), (2, 5, 7), (2, 5, 8), (2, 5, 9), (2, 6), (2, 6, 7), (2, 6, 8), (2, 6, 9), (2, 7), (2, 8), (2, 9), (3,), (3, 4), (3, 4, 7), (3, 4, 8), (3, 4, 9), (3, 5), (3, 5, 7), (3, 5, 8), (3, 5, 9), (3, 6), (3, 6, 7), (3, 6, 8), (3, 6, 9), (3, 7), (3, 8), (3, 9), (4,), (4, 7), (4, 8), (4, 9), (5,), (5, 7), (5, 8), (5, 9), (6,), (6, 7), (6, 8), (6, 9), (7,), (8,), (9,)]
add a comment |
You can use recursion with a generator:
data = [(1,2,3), (4,5,6), (7,8,9)]
def combos(d, c = []):
if len(c) == len(d):
yield c
else:
for i in d:
if i not in c:
yield from combos(d, c+[i])
def product(d, c = []):
if c:
yield tuple(c)
if d:
for i in d[0]:
yield from product(d[1:], c+[i])
result = sorted(i for b in combos(data) for i in product(b))
final_result = [a for i, a in enumerate(result) if all(len(c) != len(a) or len(set(c)&set(a)) != len(a) for c in result[:i])]
Output:
[(1,), (1, 4), (1, 4, 7), (1, 4, 8), (1, 4, 9), (1, 5), (1, 5, 7), (1, 5, 8), (1, 5, 9), (1, 6), (1, 6, 7), (1, 6, 8), (1, 6, 9), (1, 7), (1, 8), (1, 9), (2,), (2, 4), (2, 4, 7), (2, 4, 8), (2, 4, 9), (2, 5), (2, 5, 7), (2, 5, 8), (2, 5, 9), (2, 6), (2, 6, 7), (2, 6, 8), (2, 6, 9), (2, 7), (2, 8), (2, 9), (3,), (3, 4), (3, 4, 7), (3, 4, 8), (3, 4, 9), (3, 5), (3, 5, 7), (3, 5, 8), (3, 5, 9), (3, 6), (3, 6, 7), (3, 6, 8), (3, 6, 9), (3, 7), (3, 8), (3, 9), (4,), (4, 7), (4, 8), (4, 9), (5,), (5, 7), (5, 8), (5, 9), (6,), (6, 7), (6, 8), (6, 9), (7,), (8,), (9,)]
You can use recursion with a generator:
data = [(1,2,3), (4,5,6), (7,8,9)]
def combos(d, c = []):
if len(c) == len(d):
yield c
else:
for i in d:
if i not in c:
yield from combos(d, c+[i])
def product(d, c = []):
if c:
yield tuple(c)
if d:
for i in d[0]:
yield from product(d[1:], c+[i])
result = sorted(i for b in combos(data) for i in product(b))
final_result = [a for i, a in enumerate(result) if all(len(c) != len(a) or len(set(c)&set(a)) != len(a) for c in result[:i])]
Output:
[(1,), (1, 4), (1, 4, 7), (1, 4, 8), (1, 4, 9), (1, 5), (1, 5, 7), (1, 5, 8), (1, 5, 9), (1, 6), (1, 6, 7), (1, 6, 8), (1, 6, 9), (1, 7), (1, 8), (1, 9), (2,), (2, 4), (2, 4, 7), (2, 4, 8), (2, 4, 9), (2, 5), (2, 5, 7), (2, 5, 8), (2, 5, 9), (2, 6), (2, 6, 7), (2, 6, 8), (2, 6, 9), (2, 7), (2, 8), (2, 9), (3,), (3, 4), (3, 4, 7), (3, 4, 8), (3, 4, 9), (3, 5), (3, 5, 7), (3, 5, 8), (3, 5, 9), (3, 6), (3, 6, 7), (3, 6, 8), (3, 6, 9), (3, 7), (3, 8), (3, 9), (4,), (4, 7), (4, 8), (4, 9), (5,), (5, 7), (5, 8), (5, 9), (6,), (6, 7), (6, 8), (6, 9), (7,), (8,), (9,)]
edited Aug 10 at 18:57
answered Aug 10 at 18:27
Ajax1234Ajax1234
47k4 gold badges31 silver badges62 bronze badges
47k4 gold badges31 silver badges62 bronze badges
add a comment |
add a comment |
Here is a non-recursive solution with a simple for
loop. Uniqueness is enforced by applying set
to the list of the outputted tuples.
lsts = [(1,2,3), (4,5,6), (7,8,9)]
res = [[]]
for lst in lsts:
res += [(*r, x) for r in res for x in lst]
# print(tuple(lst) for lst in res[1:])
# (5, 9), (4, 7), (6, 9), (1, 4, 7), (2, 6, 9), (4, 8), (3, 4, 7), (2,
# 8), (2, 6, 8), (9,), (2, 5, 8), (1, 6), (3, 6, 8), (2, 5, 9), (3, 5,
# 9), (3, 7), (2, 5), (3, 6, 9), (5, 8), (1, 6, 8), (3, 5, 8), (2, 6,
# 7), (4, 9), (6, 7), (1,), (2, 9), (1, 6, 9), (3,), (1, 5), (5,), (3,
# 6), (7,), (3, 6, 7), (1, 5, 9), (2, 6), (2, 4, 7), (1, 5, 8), (3, 4,
# 8), (8,), (3, 4, 9), (1, 4), (1, 6, 7), (3, 9), (1, 9), (2, 5, 7), (3,
# 5), (2, 7), (2, 4, 9), (6, 8), (1, 5, 7), (2,), (2, 4, 8), (5, 7), (1,
# 4, 8), (3, 5, 7), (4,), (3, 8), (1, 8), (1, 4, 9), (6,), (1, 7), (3,
# 4), (2, 4)
Great solution! Only three lines of pure Python code, no imports necessary, by far the fastest solution and currently the only one that also includes the empty set (which should be part of the solution, IMHO).
– wovano
Aug 11 at 10:05
BTW: You mention that uniqueness is enforced by applyingset
, but I think the list is already correct (i.e. contains only unique values, no duplicates).
– wovano
Aug 11 at 10:06
1
Thanks. There may be duplicates for other input values, like[(1,2,3), (1,2,4), (1,2,5)]
. I also dropped the empty list (res[0]
) before passing to set by analogy to the original example, but I agree that the rules are unclear on this.
– hilberts_drinking_problem
Aug 11 at 16:22
add a comment |
Here is a non-recursive solution with a simple for
loop. Uniqueness is enforced by applying set
to the list of the outputted tuples.
lsts = [(1,2,3), (4,5,6), (7,8,9)]
res = [[]]
for lst in lsts:
res += [(*r, x) for r in res for x in lst]
# print(tuple(lst) for lst in res[1:])
# (5, 9), (4, 7), (6, 9), (1, 4, 7), (2, 6, 9), (4, 8), (3, 4, 7), (2,
# 8), (2, 6, 8), (9,), (2, 5, 8), (1, 6), (3, 6, 8), (2, 5, 9), (3, 5,
# 9), (3, 7), (2, 5), (3, 6, 9), (5, 8), (1, 6, 8), (3, 5, 8), (2, 6,
# 7), (4, 9), (6, 7), (1,), (2, 9), (1, 6, 9), (3,), (1, 5), (5,), (3,
# 6), (7,), (3, 6, 7), (1, 5, 9), (2, 6), (2, 4, 7), (1, 5, 8), (3, 4,
# 8), (8,), (3, 4, 9), (1, 4), (1, 6, 7), (3, 9), (1, 9), (2, 5, 7), (3,
# 5), (2, 7), (2, 4, 9), (6, 8), (1, 5, 7), (2,), (2, 4, 8), (5, 7), (1,
# 4, 8), (3, 5, 7), (4,), (3, 8), (1, 8), (1, 4, 9), (6,), (1, 7), (3,
# 4), (2, 4)
Great solution! Only three lines of pure Python code, no imports necessary, by far the fastest solution and currently the only one that also includes the empty set (which should be part of the solution, IMHO).
– wovano
Aug 11 at 10:05
BTW: You mention that uniqueness is enforced by applyingset
, but I think the list is already correct (i.e. contains only unique values, no duplicates).
– wovano
Aug 11 at 10:06
1
Thanks. There may be duplicates for other input values, like[(1,2,3), (1,2,4), (1,2,5)]
. I also dropped the empty list (res[0]
) before passing to set by analogy to the original example, but I agree that the rules are unclear on this.
– hilberts_drinking_problem
Aug 11 at 16:22
add a comment |
Here is a non-recursive solution with a simple for
loop. Uniqueness is enforced by applying set
to the list of the outputted tuples.
lsts = [(1,2,3), (4,5,6), (7,8,9)]
res = [[]]
for lst in lsts:
res += [(*r, x) for r in res for x in lst]
# print(tuple(lst) for lst in res[1:])
# (5, 9), (4, 7), (6, 9), (1, 4, 7), (2, 6, 9), (4, 8), (3, 4, 7), (2,
# 8), (2, 6, 8), (9,), (2, 5, 8), (1, 6), (3, 6, 8), (2, 5, 9), (3, 5,
# 9), (3, 7), (2, 5), (3, 6, 9), (5, 8), (1, 6, 8), (3, 5, 8), (2, 6,
# 7), (4, 9), (6, 7), (1,), (2, 9), (1, 6, 9), (3,), (1, 5), (5,), (3,
# 6), (7,), (3, 6, 7), (1, 5, 9), (2, 6), (2, 4, 7), (1, 5, 8), (3, 4,
# 8), (8,), (3, 4, 9), (1, 4), (1, 6, 7), (3, 9), (1, 9), (2, 5, 7), (3,
# 5), (2, 7), (2, 4, 9), (6, 8), (1, 5, 7), (2,), (2, 4, 8), (5, 7), (1,
# 4, 8), (3, 5, 7), (4,), (3, 8), (1, 8), (1, 4, 9), (6,), (1, 7), (3,
# 4), (2, 4)
Here is a non-recursive solution with a simple for
loop. Uniqueness is enforced by applying set
to the list of the outputted tuples.
lsts = [(1,2,3), (4,5,6), (7,8,9)]
res = [[]]
for lst in lsts:
res += [(*r, x) for r in res for x in lst]
# print(tuple(lst) for lst in res[1:])
# (5, 9), (4, 7), (6, 9), (1, 4, 7), (2, 6, 9), (4, 8), (3, 4, 7), (2,
# 8), (2, 6, 8), (9,), (2, 5, 8), (1, 6), (3, 6, 8), (2, 5, 9), (3, 5,
# 9), (3, 7), (2, 5), (3, 6, 9), (5, 8), (1, 6, 8), (3, 5, 8), (2, 6,
# 7), (4, 9), (6, 7), (1,), (2, 9), (1, 6, 9), (3,), (1, 5), (5,), (3,
# 6), (7,), (3, 6, 7), (1, 5, 9), (2, 6), (2, 4, 7), (1, 5, 8), (3, 4,
# 8), (8,), (3, 4, 9), (1, 4), (1, 6, 7), (3, 9), (1, 9), (2, 5, 7), (3,
# 5), (2, 7), (2, 4, 9), (6, 8), (1, 5, 7), (2,), (2, 4, 8), (5, 7), (1,
# 4, 8), (3, 5, 7), (4,), (3, 8), (1, 8), (1, 4, 9), (6,), (1, 7), (3,
# 4), (2, 4)
edited Aug 11 at 7:40
answered Aug 10 at 20:18
hilberts_drinking_problemhilberts_drinking_problem
7,0893 gold badges14 silver badges35 bronze badges
7,0893 gold badges14 silver badges35 bronze badges
Great solution! Only three lines of pure Python code, no imports necessary, by far the fastest solution and currently the only one that also includes the empty set (which should be part of the solution, IMHO).
– wovano
Aug 11 at 10:05
BTW: You mention that uniqueness is enforced by applyingset
, but I think the list is already correct (i.e. contains only unique values, no duplicates).
– wovano
Aug 11 at 10:06
1
Thanks. There may be duplicates for other input values, like[(1,2,3), (1,2,4), (1,2,5)]
. I also dropped the empty list (res[0]
) before passing to set by analogy to the original example, but I agree that the rules are unclear on this.
– hilberts_drinking_problem
Aug 11 at 16:22
add a comment |
Great solution! Only three lines of pure Python code, no imports necessary, by far the fastest solution and currently the only one that also includes the empty set (which should be part of the solution, IMHO).
– wovano
Aug 11 at 10:05
BTW: You mention that uniqueness is enforced by applyingset
, but I think the list is already correct (i.e. contains only unique values, no duplicates).
– wovano
Aug 11 at 10:06
1
Thanks. There may be duplicates for other input values, like[(1,2,3), (1,2,4), (1,2,5)]
. I also dropped the empty list (res[0]
) before passing to set by analogy to the original example, but I agree that the rules are unclear on this.
– hilberts_drinking_problem
Aug 11 at 16:22
Great solution! Only three lines of pure Python code, no imports necessary, by far the fastest solution and currently the only one that also includes the empty set (which should be part of the solution, IMHO).
– wovano
Aug 11 at 10:05
Great solution! Only three lines of pure Python code, no imports necessary, by far the fastest solution and currently the only one that also includes the empty set (which should be part of the solution, IMHO).
– wovano
Aug 11 at 10:05
BTW: You mention that uniqueness is enforced by applying
set
, but I think the list is already correct (i.e. contains only unique values, no duplicates).– wovano
Aug 11 at 10:06
BTW: You mention that uniqueness is enforced by applying
set
, but I think the list is already correct (i.e. contains only unique values, no duplicates).– wovano
Aug 11 at 10:06
1
1
Thanks. There may be duplicates for other input values, like
[(1,2,3), (1,2,4), (1,2,5)]
. I also dropped the empty list (res[0]
) before passing to set by analogy to the original example, but I agree that the rules are unclear on this.– hilberts_drinking_problem
Aug 11 at 16:22
Thanks. There may be duplicates for other input values, like
[(1,2,3), (1,2,4), (1,2,5)]
. I also dropped the empty list (res[0]
) before passing to set by analogy to the original example, but I agree that the rules are unclear on this.– hilberts_drinking_problem
Aug 11 at 16:22
add a comment |
Using itertools:
import itertools as it
def all_combinations(groups):
result = set()
for prod in it.product(*groups):
for length in range(1, len(groups) + 1):
result.update(it.combinations(prod, length))
return result
all_combinations([(1,2,3), (4,5,6), (7,8,9)])
add a comment |
Using itertools:
import itertools as it
def all_combinations(groups):
result = set()
for prod in it.product(*groups):
for length in range(1, len(groups) + 1):
result.update(it.combinations(prod, length))
return result
all_combinations([(1,2,3), (4,5,6), (7,8,9)])
add a comment |
Using itertools:
import itertools as it
def all_combinations(groups):
result = set()
for prod in it.product(*groups):
for length in range(1, len(groups) + 1):
result.update(it.combinations(prod, length))
return result
all_combinations([(1,2,3), (4,5,6), (7,8,9)])
Using itertools:
import itertools as it
def all_combinations(groups):
result = set()
for prod in it.product(*groups):
for length in range(1, len(groups) + 1):
result.update(it.combinations(prod, length))
return result
all_combinations([(1,2,3), (4,5,6), (7,8,9)])
edited Aug 10 at 18:42
answered Aug 10 at 18:35
eumiroeumiro
140k22 gold badges245 silver badges237 bronze badges
140k22 gold badges245 silver badges237 bronze badges
add a comment |
add a comment |
Another version:
from itertools import product, combinations
lst = [(1,2,3), (4,5,6), (7,8,9)]
def generate(lst):
for idx in range(len(lst)):
for val in lst[idx]:
yield (val,)
for j in range(1, len(lst)):
for c in combinations(lst[idx+1:], j):
yield from tuple((val,) + i for i in product(*c))
l = [*generate(lst)]
print(l)
Prints:
[(1,), (1, 4), (1, 5), (1, 6), (1, 7), (1, 8), (1, 9), (1, 4, 7), (1, 4, 8), (1, 4, 9), (1, 5, 7), (1, 5, 8), (1, 5, 9), (1, 6, 7), (1, 6, 8), (1, 6, 9), (2,), (2, 4), (2, 5), (2, 6), (2, 7), (2, 8), (2, 9), (2, 4, 7), (2, 4, 8), (2, 4, 9), (2, 5, 7), (2, 5, 8), (2, 5, 9), (2, 6, 7), (2, 6, 8), (2, 6, 9), (3,), (3, 4), (3, 5), (3, 6), (3, 7), (3, 8), (3, 9), (3, 4, 7), (3, 4, 8), (3, 4, 9), (3, 5, 7), (3, 5, 8), (3, 5, 9), (3, 6, 7), (3, 6, 8), (3, 6, 9), (4,), (4, 7), (4, 8), (4, 9), (5,), (5, 7), (5, 8), (5, 9), (6,), (6, 7), (6, 8), (6, 9), (7,), (8,), (9,)]
add a comment |
Another version:
from itertools import product, combinations
lst = [(1,2,3), (4,5,6), (7,8,9)]
def generate(lst):
for idx in range(len(lst)):
for val in lst[idx]:
yield (val,)
for j in range(1, len(lst)):
for c in combinations(lst[idx+1:], j):
yield from tuple((val,) + i for i in product(*c))
l = [*generate(lst)]
print(l)
Prints:
[(1,), (1, 4), (1, 5), (1, 6), (1, 7), (1, 8), (1, 9), (1, 4, 7), (1, 4, 8), (1, 4, 9), (1, 5, 7), (1, 5, 8), (1, 5, 9), (1, 6, 7), (1, 6, 8), (1, 6, 9), (2,), (2, 4), (2, 5), (2, 6), (2, 7), (2, 8), (2, 9), (2, 4, 7), (2, 4, 8), (2, 4, 9), (2, 5, 7), (2, 5, 8), (2, 5, 9), (2, 6, 7), (2, 6, 8), (2, 6, 9), (3,), (3, 4), (3, 5), (3, 6), (3, 7), (3, 8), (3, 9), (3, 4, 7), (3, 4, 8), (3, 4, 9), (3, 5, 7), (3, 5, 8), (3, 5, 9), (3, 6, 7), (3, 6, 8), (3, 6, 9), (4,), (4, 7), (4, 8), (4, 9), (5,), (5, 7), (5, 8), (5, 9), (6,), (6, 7), (6, 8), (6, 9), (7,), (8,), (9,)]
add a comment |
Another version:
from itertools import product, combinations
lst = [(1,2,3), (4,5,6), (7,8,9)]
def generate(lst):
for idx in range(len(lst)):
for val in lst[idx]:
yield (val,)
for j in range(1, len(lst)):
for c in combinations(lst[idx+1:], j):
yield from tuple((val,) + i for i in product(*c))
l = [*generate(lst)]
print(l)
Prints:
[(1,), (1, 4), (1, 5), (1, 6), (1, 7), (1, 8), (1, 9), (1, 4, 7), (1, 4, 8), (1, 4, 9), (1, 5, 7), (1, 5, 8), (1, 5, 9), (1, 6, 7), (1, 6, 8), (1, 6, 9), (2,), (2, 4), (2, 5), (2, 6), (2, 7), (2, 8), (2, 9), (2, 4, 7), (2, 4, 8), (2, 4, 9), (2, 5, 7), (2, 5, 8), (2, 5, 9), (2, 6, 7), (2, 6, 8), (2, 6, 9), (3,), (3, 4), (3, 5), (3, 6), (3, 7), (3, 8), (3, 9), (3, 4, 7), (3, 4, 8), (3, 4, 9), (3, 5, 7), (3, 5, 8), (3, 5, 9), (3, 6, 7), (3, 6, 8), (3, 6, 9), (4,), (4, 7), (4, 8), (4, 9), (5,), (5, 7), (5, 8), (5, 9), (6,), (6, 7), (6, 8), (6, 9), (7,), (8,), (9,)]
Another version:
from itertools import product, combinations
lst = [(1,2,3), (4,5,6), (7,8,9)]
def generate(lst):
for idx in range(len(lst)):
for val in lst[idx]:
yield (val,)
for j in range(1, len(lst)):
for c in combinations(lst[idx+1:], j):
yield from tuple((val,) + i for i in product(*c))
l = [*generate(lst)]
print(l)
Prints:
[(1,), (1, 4), (1, 5), (1, 6), (1, 7), (1, 8), (1, 9), (1, 4, 7), (1, 4, 8), (1, 4, 9), (1, 5, 7), (1, 5, 8), (1, 5, 9), (1, 6, 7), (1, 6, 8), (1, 6, 9), (2,), (2, 4), (2, 5), (2, 6), (2, 7), (2, 8), (2, 9), (2, 4, 7), (2, 4, 8), (2, 4, 9), (2, 5, 7), (2, 5, 8), (2, 5, 9), (2, 6, 7), (2, 6, 8), (2, 6, 9), (3,), (3, 4), (3, 5), (3, 6), (3, 7), (3, 8), (3, 9), (3, 4, 7), (3, 4, 8), (3, 4, 9), (3, 5, 7), (3, 5, 8), (3, 5, 9), (3, 6, 7), (3, 6, 8), (3, 6, 9), (4,), (4, 7), (4, 8), (4, 9), (5,), (5, 7), (5, 8), (5, 9), (6,), (6, 7), (6, 8), (6, 9), (7,), (8,), (9,)]
edited Aug 11 at 10:07
answered Aug 10 at 18:48
Andrej KeselyAndrej Kesely
20k3 gold badges12 silver badges36 bronze badges
20k3 gold badges12 silver badges36 bronze badges
add a comment |
add a comment |
Thank to @wovano for clarifying rule 2. This makes the solution even more shorter:
from itertools import chain, combinations, product
blubb = [(1, 2, 3), (4, 5, 6), (7, 8, 9)]
set_combos = chain.from_iterable(combinations(blubb, i) for i in range(len(blubb) + 1))
result_func = list(chain.from_iterable(map(lambda x: product(*x), set_combos)))
And as a bonus a speed comparison. @hilberts_drinking_problem's solution is awesome but there is an overhead.
def pure_python(list_of_tuples):
res = [tuple()]
for lst in list_of_tuples:
res += [(*r, x) for r in res for x in lst]
return res
def with_itertools(list_of_tuples):
set_combos = chain.from_iterable(combinations(list_of_tuples, i) for i in range(len(list_of_tuples) + 1))
return list(chain.from_iterable(map(lambda x: product(*x), set_combos)))
assert sorted(with_itertools(blubb), key=str) == sorted(pure_python(blubb), key=str)
Both computes the same stuff, but...
%timeit with_itertools(blubb)
7.18 µs ± 11.3 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
%timeit pure_python(blubb)
10.5 µs ± 46 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
although for small samples itertools
are little bit faster there is a large gap when the set grows:
import toolz
large_blubb = list(toolz.partition_all(3, range(3*10)))
assert sorted(with_itertools(large_blubb), key=str) == sorted(pure_python(large_blubb), key=str)
%timeit with_itertools(large_blubb)
106 ms ± 307 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
%timeit pure_python(large_blubb)
262 ms ± 1.85 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
which makes itertools
's solution 2,5 times faster.
Edit: corrected according to rule 2. Plus speed comparison
Edit: fix yet another mistake - now the speed comparison is realistic
It seems you didn't understand the problem completely. Double-check the last requirement: "combinations which derive from the same tuples are not allowed". So it means you should use 0 or 1 element from(1,2,3)
plus 0 or 1 element from(4,5,6)
and 0 or 1 element from(7,8,9)
. See the output of the other answers as reference. Your solution returns invalid combinations such as(1,2,4)
as well.
– wovano
Aug 11 at 9:56
Thank you @wovano for the explanation! I edited the answer. Now it should run according to the rules.
– Drey
Aug 11 at 12:31
Nice improvement!! I would change the 3th line toset_combos = chain.from_iterable(combinations(blubb, i) for i in range(len(blubb) + 1))
, so that it works for arbitrary input length instead of fixed length of 3. It'll also add the empty list, so you don't have to add it manually (e.g. remove[[]] +
) on the next line. You're right that your solution is much faster for large input sets. Well done :-)
– wovano
Aug 11 at 13:31
Thanks for the suggestions. Instead oflen(blubb)+1
I usedlen(blubb[0])+1
if I understand correctly.
– Drey
Aug 11 at 14:39
No, it really must belen(blubb)
and notlen(blubb[0])
, because you are creating combinations of sets (sets of numbers, not Pythonset
s), so you have to specify the number of sets, which islen(blubb)
. NB: Why the name blubb?? A more descriptive name might be helpful ;-)
– wovano
Aug 11 at 15:22
|
show 1 more comment
Thank to @wovano for clarifying rule 2. This makes the solution even more shorter:
from itertools import chain, combinations, product
blubb = [(1, 2, 3), (4, 5, 6), (7, 8, 9)]
set_combos = chain.from_iterable(combinations(blubb, i) for i in range(len(blubb) + 1))
result_func = list(chain.from_iterable(map(lambda x: product(*x), set_combos)))
And as a bonus a speed comparison. @hilberts_drinking_problem's solution is awesome but there is an overhead.
def pure_python(list_of_tuples):
res = [tuple()]
for lst in list_of_tuples:
res += [(*r, x) for r in res for x in lst]
return res
def with_itertools(list_of_tuples):
set_combos = chain.from_iterable(combinations(list_of_tuples, i) for i in range(len(list_of_tuples) + 1))
return list(chain.from_iterable(map(lambda x: product(*x), set_combos)))
assert sorted(with_itertools(blubb), key=str) == sorted(pure_python(blubb), key=str)
Both computes the same stuff, but...
%timeit with_itertools(blubb)
7.18 µs ± 11.3 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
%timeit pure_python(blubb)
10.5 µs ± 46 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
although for small samples itertools
are little bit faster there is a large gap when the set grows:
import toolz
large_blubb = list(toolz.partition_all(3, range(3*10)))
assert sorted(with_itertools(large_blubb), key=str) == sorted(pure_python(large_blubb), key=str)
%timeit with_itertools(large_blubb)
106 ms ± 307 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
%timeit pure_python(large_blubb)
262 ms ± 1.85 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
which makes itertools
's solution 2,5 times faster.
Edit: corrected according to rule 2. Plus speed comparison
Edit: fix yet another mistake - now the speed comparison is realistic
It seems you didn't understand the problem completely. Double-check the last requirement: "combinations which derive from the same tuples are not allowed". So it means you should use 0 or 1 element from(1,2,3)
plus 0 or 1 element from(4,5,6)
and 0 or 1 element from(7,8,9)
. See the output of the other answers as reference. Your solution returns invalid combinations such as(1,2,4)
as well.
– wovano
Aug 11 at 9:56
Thank you @wovano for the explanation! I edited the answer. Now it should run according to the rules.
– Drey
Aug 11 at 12:31
Nice improvement!! I would change the 3th line toset_combos = chain.from_iterable(combinations(blubb, i) for i in range(len(blubb) + 1))
, so that it works for arbitrary input length instead of fixed length of 3. It'll also add the empty list, so you don't have to add it manually (e.g. remove[[]] +
) on the next line. You're right that your solution is much faster for large input sets. Well done :-)
– wovano
Aug 11 at 13:31
Thanks for the suggestions. Instead oflen(blubb)+1
I usedlen(blubb[0])+1
if I understand correctly.
– Drey
Aug 11 at 14:39
No, it really must belen(blubb)
and notlen(blubb[0])
, because you are creating combinations of sets (sets of numbers, not Pythonset
s), so you have to specify the number of sets, which islen(blubb)
. NB: Why the name blubb?? A more descriptive name might be helpful ;-)
– wovano
Aug 11 at 15:22
|
show 1 more comment
Thank to @wovano for clarifying rule 2. This makes the solution even more shorter:
from itertools import chain, combinations, product
blubb = [(1, 2, 3), (4, 5, 6), (7, 8, 9)]
set_combos = chain.from_iterable(combinations(blubb, i) for i in range(len(blubb) + 1))
result_func = list(chain.from_iterable(map(lambda x: product(*x), set_combos)))
And as a bonus a speed comparison. @hilberts_drinking_problem's solution is awesome but there is an overhead.
def pure_python(list_of_tuples):
res = [tuple()]
for lst in list_of_tuples:
res += [(*r, x) for r in res for x in lst]
return res
def with_itertools(list_of_tuples):
set_combos = chain.from_iterable(combinations(list_of_tuples, i) for i in range(len(list_of_tuples) + 1))
return list(chain.from_iterable(map(lambda x: product(*x), set_combos)))
assert sorted(with_itertools(blubb), key=str) == sorted(pure_python(blubb), key=str)
Both computes the same stuff, but...
%timeit with_itertools(blubb)
7.18 µs ± 11.3 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
%timeit pure_python(blubb)
10.5 µs ± 46 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
although for small samples itertools
are little bit faster there is a large gap when the set grows:
import toolz
large_blubb = list(toolz.partition_all(3, range(3*10)))
assert sorted(with_itertools(large_blubb), key=str) == sorted(pure_python(large_blubb), key=str)
%timeit with_itertools(large_blubb)
106 ms ± 307 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
%timeit pure_python(large_blubb)
262 ms ± 1.85 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
which makes itertools
's solution 2,5 times faster.
Edit: corrected according to rule 2. Plus speed comparison
Edit: fix yet another mistake - now the speed comparison is realistic
Thank to @wovano for clarifying rule 2. This makes the solution even more shorter:
from itertools import chain, combinations, product
blubb = [(1, 2, 3), (4, 5, 6), (7, 8, 9)]
set_combos = chain.from_iterable(combinations(blubb, i) for i in range(len(blubb) + 1))
result_func = list(chain.from_iterable(map(lambda x: product(*x), set_combos)))
And as a bonus a speed comparison. @hilberts_drinking_problem's solution is awesome but there is an overhead.
def pure_python(list_of_tuples):
res = [tuple()]
for lst in list_of_tuples:
res += [(*r, x) for r in res for x in lst]
return res
def with_itertools(list_of_tuples):
set_combos = chain.from_iterable(combinations(list_of_tuples, i) for i in range(len(list_of_tuples) + 1))
return list(chain.from_iterable(map(lambda x: product(*x), set_combos)))
assert sorted(with_itertools(blubb), key=str) == sorted(pure_python(blubb), key=str)
Both computes the same stuff, but...
%timeit with_itertools(blubb)
7.18 µs ± 11.3 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
%timeit pure_python(blubb)
10.5 µs ± 46 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
although for small samples itertools
are little bit faster there is a large gap when the set grows:
import toolz
large_blubb = list(toolz.partition_all(3, range(3*10)))
assert sorted(with_itertools(large_blubb), key=str) == sorted(pure_python(large_blubb), key=str)
%timeit with_itertools(large_blubb)
106 ms ± 307 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
%timeit pure_python(large_blubb)
262 ms ± 1.85 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
which makes itertools
's solution 2,5 times faster.
Edit: corrected according to rule 2. Plus speed comparison
Edit: fix yet another mistake - now the speed comparison is realistic
edited Aug 11 at 17:05
answered Aug 10 at 19:32
DreyDrey
2,04715 silver badges18 bronze badges
2,04715 silver badges18 bronze badges
It seems you didn't understand the problem completely. Double-check the last requirement: "combinations which derive from the same tuples are not allowed". So it means you should use 0 or 1 element from(1,2,3)
plus 0 or 1 element from(4,5,6)
and 0 or 1 element from(7,8,9)
. See the output of the other answers as reference. Your solution returns invalid combinations such as(1,2,4)
as well.
– wovano
Aug 11 at 9:56
Thank you @wovano for the explanation! I edited the answer. Now it should run according to the rules.
– Drey
Aug 11 at 12:31
Nice improvement!! I would change the 3th line toset_combos = chain.from_iterable(combinations(blubb, i) for i in range(len(blubb) + 1))
, so that it works for arbitrary input length instead of fixed length of 3. It'll also add the empty list, so you don't have to add it manually (e.g. remove[[]] +
) on the next line. You're right that your solution is much faster for large input sets. Well done :-)
– wovano
Aug 11 at 13:31
Thanks for the suggestions. Instead oflen(blubb)+1
I usedlen(blubb[0])+1
if I understand correctly.
– Drey
Aug 11 at 14:39
No, it really must belen(blubb)
and notlen(blubb[0])
, because you are creating combinations of sets (sets of numbers, not Pythonset
s), so you have to specify the number of sets, which islen(blubb)
. NB: Why the name blubb?? A more descriptive name might be helpful ;-)
– wovano
Aug 11 at 15:22
|
show 1 more comment
It seems you didn't understand the problem completely. Double-check the last requirement: "combinations which derive from the same tuples are not allowed". So it means you should use 0 or 1 element from(1,2,3)
plus 0 or 1 element from(4,5,6)
and 0 or 1 element from(7,8,9)
. See the output of the other answers as reference. Your solution returns invalid combinations such as(1,2,4)
as well.
– wovano
Aug 11 at 9:56
Thank you @wovano for the explanation! I edited the answer. Now it should run according to the rules.
– Drey
Aug 11 at 12:31
Nice improvement!! I would change the 3th line toset_combos = chain.from_iterable(combinations(blubb, i) for i in range(len(blubb) + 1))
, so that it works for arbitrary input length instead of fixed length of 3. It'll also add the empty list, so you don't have to add it manually (e.g. remove[[]] +
) on the next line. You're right that your solution is much faster for large input sets. Well done :-)
– wovano
Aug 11 at 13:31
Thanks for the suggestions. Instead oflen(blubb)+1
I usedlen(blubb[0])+1
if I understand correctly.
– Drey
Aug 11 at 14:39
No, it really must belen(blubb)
and notlen(blubb[0])
, because you are creating combinations of sets (sets of numbers, not Pythonset
s), so you have to specify the number of sets, which islen(blubb)
. NB: Why the name blubb?? A more descriptive name might be helpful ;-)
– wovano
Aug 11 at 15:22
It seems you didn't understand the problem completely. Double-check the last requirement: "combinations which derive from the same tuples are not allowed". So it means you should use 0 or 1 element from
(1,2,3)
plus 0 or 1 element from (4,5,6)
and 0 or 1 element from (7,8,9)
. See the output of the other answers as reference. Your solution returns invalid combinations such as (1,2,4)
as well.– wovano
Aug 11 at 9:56
It seems you didn't understand the problem completely. Double-check the last requirement: "combinations which derive from the same tuples are not allowed". So it means you should use 0 or 1 element from
(1,2,3)
plus 0 or 1 element from (4,5,6)
and 0 or 1 element from (7,8,9)
. See the output of the other answers as reference. Your solution returns invalid combinations such as (1,2,4)
as well.– wovano
Aug 11 at 9:56
Thank you @wovano for the explanation! I edited the answer. Now it should run according to the rules.
– Drey
Aug 11 at 12:31
Thank you @wovano for the explanation! I edited the answer. Now it should run according to the rules.
– Drey
Aug 11 at 12:31
Nice improvement!! I would change the 3th line to
set_combos = chain.from_iterable(combinations(blubb, i) for i in range(len(blubb) + 1))
, so that it works for arbitrary input length instead of fixed length of 3. It'll also add the empty list, so you don't have to add it manually (e.g. remove [[]] +
) on the next line. You're right that your solution is much faster for large input sets. Well done :-)– wovano
Aug 11 at 13:31
Nice improvement!! I would change the 3th line to
set_combos = chain.from_iterable(combinations(blubb, i) for i in range(len(blubb) + 1))
, so that it works for arbitrary input length instead of fixed length of 3. It'll also add the empty list, so you don't have to add it manually (e.g. remove [[]] +
) on the next line. You're right that your solution is much faster for large input sets. Well done :-)– wovano
Aug 11 at 13:31
Thanks for the suggestions. Instead of
len(blubb)+1
I used len(blubb[0])+1
if I understand correctly.– Drey
Aug 11 at 14:39
Thanks for the suggestions. Instead of
len(blubb)+1
I used len(blubb[0])+1
if I understand correctly.– Drey
Aug 11 at 14:39
No, it really must be
len(blubb)
and not len(blubb[0])
, because you are creating combinations of sets (sets of numbers, not Python set
s), so you have to specify the number of sets, which is len(blubb)
. NB: Why the name blubb?? A more descriptive name might be helpful ;-)– wovano
Aug 11 at 15:22
No, it really must be
len(blubb)
and not len(blubb[0])
, because you are creating combinations of sets (sets of numbers, not Python set
s), so you have to specify the number of sets, which is len(blubb)
. NB: Why the name blubb?? A more descriptive name might be helpful ;-)– wovano
Aug 11 at 15:22
|
show 1 more comment
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f57444657%2funique-combinations-of-a-list-of-tuples%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
But wait, why
(1)
to(9)
are part of the soultion if(1,2)
is not allowed given the second rule ?– Drey
Aug 10 at 19:26
It looks like there are three sets of tuples: 1)
[(x,) for x in the_list[0]]
, 2)[(x,y) for x in the_list[0] for y in the_list[1]]
, and 3)[(x,y,z) for x in the_list[0] for y in the_list[1] for z in the_list[2]]
.– chepner
Aug 10 at 19:50
Possible duplicate of Picking unordered combinations from pools with overlap
– Joseph Wood
Aug 10 at 19:52