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;








10















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))









share|improve this question


























  • 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

















10















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))









share|improve this question


























  • 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













10












10








10


2






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))









share|improve this question
















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






share|improve this question















share|improve this question













share|improve this question




share|improve this question








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

















  • 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












5 Answers
5






active

oldest

votes


















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,)]





share|improve this answer


































    5















    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)





    share|improve this answer



























    • 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






    • 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


















    3















    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)])





    share|improve this answer


































      1















      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,)]





      share|improve this answer


































        1















        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






        share|improve this answer



























        • 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 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











        • No, it really must be len(blubb) and not len(blubb[0]), because you are creating combinations of sets (sets of numbers, not Python sets), 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













        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
        );



        );













        draft saved

        draft discarded


















        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









        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,)]





        share|improve this answer































          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,)]





          share|improve this answer





























            9














            9










            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,)]





            share|improve this answer















            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,)]






            share|improve this answer














            share|improve this answer



            share|improve this answer








            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


























                5















                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)





                share|improve this answer



























                • 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






                • 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















                5















                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)





                share|improve this answer



























                • 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






                • 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













                5














                5










                5









                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)





                share|improve this answer















                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)






                share|improve this answer














                share|improve this answer



                share|improve this answer








                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 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





                  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











                • 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





                  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











                3















                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)])





                share|improve this answer































                  3















                  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)])





                  share|improve this answer





























                    3














                    3










                    3









                    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)])





                    share|improve this answer















                    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)])






                    share|improve this answer














                    share|improve this answer



                    share|improve this answer








                    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
























                        1















                        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,)]





                        share|improve this answer































                          1















                          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,)]





                          share|improve this answer





























                            1














                            1










                            1









                            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,)]





                            share|improve this answer















                            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,)]






                            share|improve this answer














                            share|improve this answer



                            share|improve this answer








                            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
























                                1















                                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






                                share|improve this answer



























                                • 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 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











                                • No, it really must be len(blubb) and not len(blubb[0]), because you are creating combinations of sets (sets of numbers, not Python sets), 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















                                1















                                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






                                share|improve this answer



























                                • 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 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











                                • No, it really must be len(blubb) and not len(blubb[0]), because you are creating combinations of sets (sets of numbers, not Python sets), 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













                                1














                                1










                                1









                                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






                                share|improve this answer















                                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







                                share|improve this answer














                                share|improve this answer



                                share|improve this answer








                                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 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











                                • No, it really must be len(blubb) and not len(blubb[0]), because you are creating combinations of sets (sets of numbers, not Python sets), 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

















                                • 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 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











                                • No, it really must be len(blubb) and not len(blubb[0]), because you are creating combinations of sets (sets of numbers, not Python sets), 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
















                                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 sets), 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 sets), 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

















                                draft saved

                                draft discarded
















































                                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.




                                draft saved


                                draft discarded














                                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





















































                                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







                                Popular posts from this blog

                                Get product attribute by attribute group code in magento 2get product attribute by product attribute group in magento 2Magento 2 Log Bundle Product Data in List Page?How to get all product attribute of a attribute group of Default attribute set?Magento 2.1 Create a filter in the product grid by new attributeMagento 2 : Get Product Attribute values By GroupMagento 2 How to get all existing values for one attributeMagento 2 get custom attribute of a single product inside a pluginMagento 2.3 How to get all the Multi Source Inventory (MSI) locations collection in custom module?Magento2: how to develop rest API to get new productsGet product attribute by attribute group code ( [attribute_group_code] ) in magento 2

                                Category:9 (number) SubcategoriesMedia in category "9 (number)"Navigation menuUpload mediaGND ID: 4485639-8Library of Congress authority ID: sh85091979ReasonatorScholiaStatistics

                                Magento 2.3: How do i solve this, Not registered handle, on custom form?How can i rewrite TierPrice Block in Magento2magento 2 captcha not rendering if I override layout xmlmain.CRITICAL: Plugin class doesn't existMagento 2 : Problem while adding custom button order view page?Magento 2.2.5: Overriding Admin Controller sales/orderMagento 2.2.5: Add, Update and Delete existing products Custom OptionsMagento 2.3 : File Upload issue in UI Component FormMagento2 Not registered handleHow to configured Form Builder Js in my custom magento 2.3.0 module?Magento 2.3. How to create image upload field in an admin form