【问题标题】:Why doesnt my cartesian product function work?为什么我的笛卡尔积函数不起作用?
【发布时间】:2017-12-18 01:42:06
【问题描述】:

考虑以下函数,其输出应该是一系列可迭代对象的笛卡尔积:

def cart(*iterables):
    out = ((e,) for e in iterables[0])
    for iterable in iterables[1:]:
        out = (e1 + (e2,) for e1 in out for e2 in iterable)
    return out

当生成器推导被列表推导替换时工作正常。当只有 2 个可迭代对象时也可以使用。但是当我尝试

print(list(cart([1, 2, 3], 'ab', [4, 5])))

我明白了

[(1, 4, 4), (1, 4, 5), (1, 5, 4), (1, 5, 5),
 (2, 4, 4), (2, 4, 5), (2, 5, 4), (2, 5, 5),
 (3, 4, 4), (3, 4, 5), (3, 5, 4), (3, 5, 5)]

为什么是这个而不是笛卡尔积?

【问题讨论】:

  • 您可以将中间结果存储在内存中(例如行之有效的列表方法),而不是推迟对那个 gen 的评估。 exp。其值在迭代中不断变化。
  • 我知道这个问题是关于在 Python 中实现笛卡尔积的算法,但以防万一有人最终在这里搜索如何在 Python 中做笛卡尔积,请注意这已经在 @ 中实现987654321@.

标签: python cartesian-product generator-expression


【解决方案1】:

您正在创建生成器表达式,直到for iterable in iterables[1:]: 循环的下一次迭代才会迭代。他们正在使用 闭包,它们在运行时被查找。

在这方面,生成器表达式本质上是小函数,它们创建自己的作用域,并且任何来自父作用域的名称都需要被视为闭包才能使其工作。 'function' 在您迭代时执行,然后才需要闭包并将其解析为所引用变量的 current 值。

所以你创建一个像这样的生成器表达式:

(e1 + (e2,) for e1 in out for e2 in iterable)

其中iterable 是取自父作用域(您的函数局部变量)的闭包。但是直到下一次循环时查找才会完成,此时iterable 是序列中的下一个元素

因此,对于[1, 2, 3], 'ab', [4, 5] 的输入,您在iterable = 'ab' 时创建了一个生成器表达式,但在您实际迭代时,for 循环已分配了一个新值,现在是iterable = [4, 5]。当您最终迭代最终(链式)生成器时,只有对 iterable 的最后一次赋值才算数。

您正在通过iterables[0], iterables[-1] * len(iterables) - 1 有效地创建产品; iterables[1]iterables[-2] 被完全跳过,全部被 iterables[-1] 替换。

您可以使用生成器函数来避免关闭问题,传入iterable 以绑定到本地:

def gen_step(out, iterable):
    for e1 in out:
        for e2 in iterable:
            yield e1 + (e2,)

def cart(*iterables):
    out = ((e,) for e in iterables[0])
    for iterable in iterables[1:]:
        out = gen_step(out, iterable)
    return out

您可以对返回生成器表达式的 lambda 执行相同的操作:

def cart(*iterables):
    out = ((e,) for e in iterables[0])
    for iterable in iterables[1:]:
        out = (lambda it=iterable: (e1 + (e2,) for e1 in out for e2 in it))()
    return out

【讨论】:

  • 替代品仍然很懒惰。不错。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多