【问题标题】:How to do a Selective Cartesian Product of a List of Lists in Python如何在 Python 中对列表列表进行选择性笛卡尔积
【发布时间】:2021-12-05 19:50:44
【问题描述】:

我正在尝试从现有列表中获取代表所有可能有序对的列表。

import itertools
list_of_lists=[[0, 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],[36, 37],[38],[39]]

理想情况下,我们只需要使用 itertools.product 来获取有序对的列表。

scenarios_list=list(itertools.product(*list_of_lists))

但是,如果我要为更大的列表列表执行此操作,我会遇到内存错误,因此对于可能存在大量不同组有序对的更大列表列表,此解决方案不可扩展。

那么,有没有一种方法可以设置一个流程,在这些有序对产生时我们可以迭代它们,在将列表附加到另一个列表之前,我们可以测试该列表是否满足特定标准(例如测试是否有一定数量的偶数,列表的总和不能等于最大值等)。如果不满足条件,则不会附加有序对,因此当我们只关心某些有序对时,不会不必要地占用内存。

【问题讨论】:

  • “在生成这些有序对时迭代它们”——这正是itertools.product(*list_of_lists) 让你做的事情。无需将所有组合存储在列表中。
  • itertools.product 是一个生成器,而不仅仅是一个数组。所以你可以遍历它,它不会在第一次调用时创建整个数组 - 不需要所有内存
  • 过滤itertools.product 的结果(不先将其转换为列表)是一种简单的方法。但是,如果它生成了这么多产品并且您最终会拒绝其中的很多产品,那么最好滚动您自己的递归生成器,该生成器会在产品被保证不符合标准时对其进行修剪。例如,如果您最多需要三个偶数并且您已经有部分 (0, 5, 6, 8),则 (10, 12, 14, 16 等) 中的任何一个都将被提前拒绝,从而为您节省大量时间。
  • @Reti43 您能否提供使用自定义生成器的示例答案?那会很有帮助。
  • 您的选择标准是什么?

标签: python for-loop list-comprehension itertools cartesian-product


【解决方案1】:

product 的递归基础实现开始:

def product(*lsts):
    if not lsts:
        yield ()
        return
    first_lst, *rest = lsts
    for element in first_lst:
        for rec_p in product(*rest):
            p = (element,) + rec_p
            yield p

[*product([1, 2], [3, 4, 5])]
# [(1, 3), (1, 4), (1, 5), (2, 3), (2, 4), (2, 5)]

现在,您可以通过过滤任何不符合条件的p 来增加它:

def product(*lsts, condition=None):
    if condition is None:
        condition = lambda tpl: True
    if not lsts:
        yield ()
        return
    first_lst, *rest = lsts
    for element in first_lst:
        for rec_p in product(*rest, condition=condition):
            p = (element,) + rec_p
            if condition(p):  # stop overproduction right where it happens
                yield p

现在您可以 - 例如 - 仅限于偶数元素:

[*product([1, 2], [3, 4, 5], condition=lambda tpl: not any(x%2 for x in tpl))]
# [(2, 4)]

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-03-24
    • 2015-12-05
    • 1970-01-01
    • 1970-01-01
    • 2021-11-15
    • 2012-08-27
    • 2017-07-15
    • 2012-01-03
    相关资源
    最近更新 更多