4

I have a list of lists that goes like

[[1,2,3],[3,4,5],[5,6,7,8]]

I want to create a program/function that creates a combinations like

1,3,5
1,3,6
1,3,7
1,3,8
1,4,5
1,4,6
.
.
.

If there's a way you can do it without using the itertools module, that would be even more appreciated.

John Kugelman
  • 349,597
  • 67
  • 533
  • 578
  • 2
    May I ask why you don't want to use the itertools module, since the `product` is exactly for that. And any implementation you do, is basically already done in itertools `product`. – Alex G Feb 11 '22 at 14:15
  • 1
    Does this answer your question? [Get the cartesian product of a series of lists?](https://stackoverflow.com/questions/533905/get-the-cartesian-product-of-a-series-of-lists) – Kelly Bundy Feb 11 '22 at 14:20
  • You could've at least used the itertools module to find out the proper name, and then it would've been easy to find it on the internet. – Kelly Bundy Feb 11 '22 at 14:23

6 Answers6

3

you can use itertools.product

import itertools
a = [[1,2,3],[3,4,5],[5,6,7,8]]
list(itertools.product(*a))
#output
[(1, 3, 5),
 (1, 3, 6),
 (1, 3, 7),
 (1, 3, 8),
 (1, 4, 5),
 (1, 4, 6),
 (1, 4, 7),
 (1, 4, 8),
 (1, 5, 5),
 (1, 5, 6),
 (1, 5, 7),
 (1, 5, 8),
 (2, 3, 5),
 (2, 3, 6),
 (2, 3, 7),
 (2, 3, 8),
 (2, 4, 5),
 (2, 4, 6),
 (2, 4, 7),
 (2, 4, 8),
 (2, 5, 5),
 (2, 5, 6),
 (2, 5, 7),
 (2, 5, 8),
 (3, 3, 5),
 (3, 3, 6),
 (3, 3, 7),
 (3, 3, 8),
 (3, 4, 5),
 (3, 4, 6),
 (3, 4, 7),
 (3, 4, 8),
 (3, 5, 5),
 (3, 5, 6),
 (3, 5, 7),
 (3, 5, 8)]
tomerar
  • 805
  • 5
  • 10
  • 1
    This is the best solution – especially since you can use the iterator as a generator... – Yaakov Bressler Feb 11 '22 at 14:14
  • @ybressler_simon You mean as an *iterator*? – Kelly Bundy Feb 11 '22 at 14:23
  • Whoops. ***You can use the generator as an iterator...*** @KellyBundy – Yaakov Bressler Feb 11 '22 at 14:35
  • @ybressler_simon There's no generator here, just an iterator. See the documentation or [try some tests](https://tio.run/##ZY7BSgNBDIbv8xS5dUdCQddqKXj2IZY9TMfZNbCdDJkIFfHZt2mrq9Bcws/3kfzlU985t9si80yHwqJAmkSZp@oG4QNEnqYUlTjXddhH@LFeU04SlOVqUa7FrF9KdVy4C/ACXXePD9j22LX4iBvbG3zCZ9z2vSvGl6frIvz2EbW5C96NRpojDCxwtBdQvHPnQHpJCOPOgU0RytqQ@n9pWH1RtVoackzG8K@yt7Pfqxt5qXy@dKP4eT4B). – Kelly Bundy Feb 11 '22 at 14:47
  • I stand corrected. Thanks for pointing that out. @KellyBundy – Yaakov Bressler Feb 11 '22 at 16:32
2

As you asked for a solution without itertools, this one is a recursive function that takes a list of any length and does the combination you need:

def combine(elems):
    if len(elems) == 0:
        return [[]]
    result = []    
    subcombinations =  combine(elems[1:])
    for x in elems[0]:
        for y in subcombinations:
            result.append([x, *y])
    return result

Or a much shorter version

def combine(elems):
    if len(elems) == 0:
        return [[]]
    return [[x, *y] for x in elems[0] for y in combine(elems[1:])]

Miguel
  • 2,130
  • 1
  • 11
  • 26
1

This is a roughly equivalent implementation of itertools.product() from documentation in case you want/need to build the function without using a library.

def product(*args, repeat=1):
    pools = [tuple(pool) for pool in args] * repeat
    result = [[]]
    for pool in pools:
        result = [x+[y] for x in result for y in pool]
    for prod in result:
        yield tuple(prod)

a = [[1,2,3],[3,4,5],[5,6,7,8]]

print(list(product(*a)))

Output:

[(1, 3, 5), (1, 3, 6), (1, 3, 7), (1, 3, 8), (1, 4, 5), (1, 4, 6), (1, 4, 7), (1, 4, 8), (1, 5, 5), (1, 5, 6), (1, 5, 7), (1, 5, 8), (2, 3, 5), (2, 3, 6), (2, 3, 7), (2, 3, 8), (2, 4, 5), (2, 4, 6), (2, 4, 7), (2, 4, 8), (2, 5, 5), (2, 5, 6), (2, 5, 7), (2, 5, 8), (3, 3, 5), (3, 3, 6), (3, 3, 7), (3, 3, 8), (3, 4, 5), (3, 4, 6), (3, 4, 7), (3, 4, 8), (3, 5, 5), (3, 5, 6), (3, 5, 7), (3, 5, 8)]

To print as you wish:

results = list(product(*a))

print('\n'.join([','.join(list(map(str, res))) for res in results]))

Output:

1,3,5
1,3,6
1,3,7
1,3,8
1,4,5
1,4,6
1,4,7
1,4,8
1,5,5
1,5,6
1,5,7
1,5,8
2,3,5
2,3,6
2,3,7
2,3,8
2,4,5
2,4,6
2,4,7
2,4,8
2,5,5
2,5,6
2,5,7
2,5,8
3,3,5
3,3,6
3,3,7
3,3,8
3,4,5
3,4,6
3,4,7
3,4,8
3,5,5
3,5,6
3,5,7
3,5,8
Synthase
  • 5,849
  • 2
  • 12
  • 34
1

Convert it into linear list and use combinations

from itertools import combinations
linearArr = [ele for ele in row for row in [[1,2,3],[3,4,5],[5,6,7,8]]]
for comb in combinations(linearArr,3):
    print(comb)

THUNDER 07
  • 521
  • 5
  • 21
0

Here is how you can use a recursive function:

def comb(arrs, i=0, numbs=[]):
    if i == len(arrs):
        print(*numbs)
        return
    for j in arrs[i]:
        comb(arrs, i + 1, numbs + [j])

arrs = [[1,2,3],[3,4,5],[5,6,7,8]]
comb(arrs)

Output:

1 3 5
1 3 6
1 3 7
1 3 8
1 4 5
1 4 6
1 4 7
1 4 8
1 5 5
1 5 6
1 5 7
1 5 8
2 3 5
2 3 6
2 3 7
2 3 8
2 4 5
2 4 6
2 4 7
2 4 8
2 5 5
2 5 6
2 5 7
2 5 8
3 3 5
3 3 6
3 3 7
3 3 8
3 4 5
3 4 6
3 4 7
3 4 8
3 5 5
3 5 6
3 5 7
3 5 8
Red
  • 26,798
  • 7
  • 36
  • 58
0

I tried two different ways, straight list comprehension and a recursive function.

The list comprehension method is the simplest but assumes your list will only have 3 elements. If you add a fourth set of numbers to your main list, the list comprehension will need to be adjusted to work with it.

In contrast the recursive function is more complicated but will handle an unlimited list of lists with the sub-lists having any number of elements. Of course, it's recursive so a limit will be reached and the time it takes to process the list of lists will be exponentially greater with each additonal list of numbers.

List Comprehension

lol = [
    [1,2,3],
    [3,4,5],
    [5,6,7,8]
]
o = [[x, y, z] for x in lol[0] for y in lol[1] for z in lol[2]]
print(repr(o))

output

[
  [1, 3, 5],
  [1, 3, 6],
  [1, 3, 7],
  [1, 3, 8],
  [1, 4, 5],
  ...
  [3, 5, 6],
  [3, 5, 7],
  [3, 5, 8]
]

Recursive function

def stich(l: list) -> list:
    def merge(a, b):
        if not a:
            return [[y,] for y in b]
        return [x + [y,] for x in a for y in b]
    ol = []
    tl = l.copy()
    while tl:
        ol = merge(ol, tl.pop(0))
    return ol


stiched_list = stich(lol)
print(repr(stiched_list))

output

[
  [1, 3, 5],
  [1, 3, 6],
  [1, 3, 7],
  [1, 3, 8],
  [1, 4, 5],
  ...
  [3, 5, 6],
  [3, 5, 7],
  [3, 5, 8]
]
Rowshi
  • 360
  • 2
  • 11