Python 仅获取从列表列表到第n个组合的所有唯一组合

Python 仅获取从列表列表到第n个组合的所有唯一组合,python,algorithm,list,Python,Algorithm,List,我有一个列表,其中每个内部列表中的变量都是指向图像的路径。通常每个内部列表的长度约为35,一个列表中有9个这样的列表。e、 g [[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,

我有一个列表,其中每个内部列表中的变量都是指向图像的路径。通常每个内部列表的长度约为35,一个列表中有9个这样的列表。e、 g

 [[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35]]
没有

我想从这个列表中生成9的唯一组合。如果我使用itertools.product,它可以工作,但需要的时间太长——它会使我的计算机崩溃。我需要的是一个能一直上升到第n个组合的东西,其中n可能是200左右。我试过这个

  list(itertools.product(*z))[:200]
其中z是我的列表列表,但它不起作用,因为它在执行切片之前先生成所有组合(速度太慢)

有没有其他有效的方法来运行这个

编辑:我应该补充一点,我需要将其转换为列表列表

基准:

布拉德:

def组合()
my_iter=itertools.product(*z)
打印([next(my_iter)用于范围(10000)内的i)]
运行('print(combos())'))
在0.021秒内调用10006个函数
订购人:标准名称
ncalls tottime percall cumtime percall文件名:lineno(函数)
1    0.000    0.000    0.021    0.021 :1()
1 0.000 0.000 0.021 0.021 gcm.py:17(组合)
1 0.002 0.002 0.004 0.004 gcm.py:19()
1 0.000 0.000 0.021 0.021{内置方法builtins.exec}
9999 0.003 0.000 0.003 0.000{内置方法内置。下一步}
2 0.016 0.008 0.016 0.008{内置方法内置.print}
1 0.000 0.000 0.000 0.000{方法'disable'的''lsprof.Profiler'对象}
最新答案:

 cProfile.run('print(list(my_gen(z, 10000)))')

 10005 function calls in 0.019 seconds

 Ordered by: standard name

 ncalls  tottime  percall  cumtime  percall filename:lineno(function)
    1    0.001    0.001    0.019    0.019 <string>:1(<module>)
10001    0.004    0.000    0.004    0.000 gcm.py:10(my_gen)
    1    0.000    0.000    0.019    0.019 {built-in method builtins.exec}
    1    0.014    0.014    0.014    0.014 {built-in method builtins.print}
    1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}
cProfile.run('print(list(my_gen(z,10000)))))
在0.019秒内调用10005个函数
订购人:标准名称
ncalls tottime percall cumtime percall文件名:lineno(函数)
1    0.001    0.001    0.019    0.019 :1()
10001 0.004 0.000 0.004 0.000 gcm.py:10(my_gen)
1 0.000 0.000 0.019 0.019{内置方法builtins.exec}
1 0.014 0.014 0.014 0.014{内置方法内置.print}
1 0.000 0.000 0.000 0.000{方法'disable'的''lsprof.Profiler'对象}
为了迈出这一步,我做了这个

   def my_gen(z, limit):
      count = 0
      for i in itertools.product(*z):
         if count < limit:
            if count % 1000 == 0:
               yield i
               count += 1
            else:
               count += 1
               continue
      else:
        raise StopIteration
def my_gen(z,限制):
计数=0
对于itertools.product(*z)中的i:
如果计数<限制:
如果计数%1000==0:
产量一
计数+=1
其他:
计数+=1
持续
其他:
提出停止迭代
试试这个:

my_iter = itertools.product(*z)
[next(my_iter) for i in range(200)]
试试这个:

my_iter = itertools.product(*z)
[next(my_iter) for i in range(200)]

不要将
itertools.product(*z)
转换为列表和切片,而是使用您自己的生成器将其包装起来:

def my_gen(z, limit):
    count = 0
    for i in itertools.product(*z):
        if count < limit:
            yield i
            count += 1
        else:
            raise StopIteration

不要将
itertools.product(*z)
转换为列表和切片,而是使用您自己的生成器将其包装起来:

def my_gen(z, limit):
    count = 0
    for i in itertools.product(*z):
        if count < limit:
            yield i
            count += 1
        else:
            raise StopIteration

前面的两个答案都有优点和缺点。在您自己的生成器中包装
itertools.product
,比每次使用列表理解但不引发StopIteration使其运行所有循环更好,直到
itertools.product
引发它

def capped_product(l, limit):
    i = itertools.product(*l)
    for _ in range(limit):
        yield next(i)
    raise StopIteration

list(capped_product(z, 200))
另一种方法是使用一个生成器,以增量方式提供所需大小的列表。例如:

z = [[1,2,3,4,5], [1,2,3,4,5], [1,2,3,4,5]]
n = 3

# First time you run it
first = [(1,1,1), (1,1,2), (1,1,3)]
# Second time you run it
second = [(1,1,4), (1,1,5), (1,2,1)]
# Third time you run it
third = [(1,2,2), (1,2,3), (1,2,4)]
# ...
每次你得到一个列表,你会得到列表z的以下n个组合。这可以通过第行完成:

def split_product(l, size):
    out = []
    for i in itertool.product(*l):
        out.append(i)
        if len(out) == size:
            yield out
            out = []

z = [[i for i in range(1, 36)] for _ in range(9)]
i = split_product(z, 200)
first = next(i)
second = next(i)
# ...

前面的两个答案都有优点和缺点。在您自己的生成器中包装
itertools.product
,比每次使用列表理解但不引发StopIteration使其运行所有循环更好,直到
itertools.product
引发它

def capped_product(l, limit):
    i = itertools.product(*l)
    for _ in range(limit):
        yield next(i)
    raise StopIteration

list(capped_product(z, 200))
另一种方法是使用一个生成器,以增量方式提供所需大小的列表。例如:

z = [[1,2,3,4,5], [1,2,3,4,5], [1,2,3,4,5]]
n = 3

# First time you run it
first = [(1,1,1), (1,1,2), (1,1,3)]
# Second time you run it
second = [(1,1,4), (1,1,5), (1,2,1)]
# Third time you run it
third = [(1,2,2), (1,2,3), (1,2,4)]
# ...
每次你得到一个列表,你会得到列表z的以下n个组合。这可以通过第行完成:

def split_product(l, size):
    out = []
    for i in itertool.product(*l):
        out.append(i)
        if len(out) == size:
            yield out
            out = []

z = [[i for i in range(1, 36)] for _ in range(9)]
i = split_product(z, 200)
first = next(i)
second = next(i)
# ...

这是正确的,请记住,这仍然会创建一个内存中包含200个元素的列表。可以通过将
[…]
更改为
(…)
来修复它。是否有任何方法可以在此基础上添加一个步骤,即,代替下一步,执行步骤,例如,20?如果对范围(20)内的i执行此
[下一步(我的iter)]
我的iter
在这个迭代器结束时并没有耗尽,所以你可以很容易地重复一遍,直到
我的iter
耗尽。布拉德-感谢这一点-我不得不把它交给深空,因为他可以更快、更容易地向它添加一个步骤…谢谢朋友。这是正确的,请记住这仍然会创建一个l在内存中有200个元素的ist。可以通过将
[…]
更改为
(…)
来修复它。是否有任何方法可以在此基础上添加一个步骤,即,代替下一步,执行步骤,例如,20?如果对范围(20)内的i执行此
[下一步(我的iter)]
我的iter
在这个迭代器结束时并没有耗尽,所以你可以很容易地一次又一次地做,直到
我的iter
耗尽。布拉德-感谢这一点-我不得不把它交给深空,因为他的速度快了几微秒,而且很容易添加一个步骤…谢谢老兄。这产生了一个足够快的生成器,但我需要转换这是一个列表,它是killer@GhostRider您可以将其转换为列表,即
列表(my_gen(..)
。它只会将结果转换为列表(即您将获得包含
n
产品的列表,而不是所有产品的列表)。如果
n
本身太大,无法放入内存,则您无法对此采取任何措施。请参阅我的更新答案。@GhostRider如果在
列表(…)中调用函数,则Brad答案中的代码与我答案中的代码具有完全相同的行为
,所以如果
n
太大,你会有完全相同的内存问题。为什么要去上面的基准测试结果-我愿意被告知我犯了一个错误!我认为你应该用StopIteration缩短电路这会足够快地生成一个生成器,但我需要将其转换为一个列表,它是killer@GhostRider你可以把它转换成to列表,即
列表(my_gen(..)
。它将