将python的列表理解扩展为嵌套的for循环-奇怪的结果

时间:2019-06-16 23:51:47

标签: python python-3.x list-comprehension

我碰到了这个函数,它从数组中返回N个值的每个组合:

def combs(a, n):
   if n == 0:
       return [[]]
   else:
       return [(x + [y]) for x in combs(a,n-1) for y in a]

出于我自己的理解,我尝试使用嵌套的for循环将其转换为函数:

def combinations(array,n):
    if n == 0:
        return [[]]
    else:
        for i in array:
            for j in combinations(array, n-1):
                return [j + [i]]

但是我得到的结果与预期不同。

>>> threes = ['aA','bB','cC']
>>> 
>>> combs(threes,2)
[['aA', 'aA'], ['aA', 'bB'], ['aA', 'cC'], ['bB', 'aA'], ['bB', 'bB'], ['bB', 'cC'], ['cC', 'aA'], ['cC', 'bB'], ['cC', 'cC']]
>>> 
>>> combinations(threes,2)
[['aA', 'aA']]
>>> 

我尝试了return [j+[i]]行的各种版本,但都没有成功。以下是一些示例:

                return (j + [i])

Traceback (most recent call last):
  File "...", line 24, in <module>
    print(combinations(threes,2))
  File "...", line 16, in combinations
    return (j + [i])
TypeError: can only concatenate str (not "list") to str

                return j + [i]

Traceback (most recent call last):
  File "...", line 24, in <module>
    print(combinations(threes,2))
  File "...", line 16, in combinations
    return j + [i]
TypeError: can only concatenate str (not "list") to str

为什么第一个函数的列表理解返回的内容与我的扩展嵌套for循环版本不同?

将第一个函数的列表理解和返回值转换为嵌套的for循环策略的正确(起作用)的方法是什么?

2 个答案:

答案 0 :(得分:4)

如果您真的想使它等效,那么您需要做一个return。当您执行理解时,您将以某种原子方式创建列表,即,只有在完全构建列表之后才能访问列表///在列表理解(构建)完成之前,无法访问列表。要在没有列表理解的情况下执行此操作,您需要填充一个可变容器,然后在末尾执行一次返回:

def combinations(array,n):
    if n == 0:
        return [[]]
    else:
        result = []
        for i in array:
            for j in combinations(array, n-1):
                result.append(j + [i])
        return result

这是解决问题的有效方法,但我还将探索创建一个生成器函数。与通常只能从一个功能return一次的普通情况不同,生成器允许您从该功能多次yield一次。

在您不想在创建过程中阻塞,不想强制使用特定容器的情况下,或者通常在简化逻辑的情况下,此策略很有用。此外,如果您只需要遍历结果而实际上并不需要一次整个列表,那么它的另一个优点是不会将整个序列加载到内存中。

通常,我发现这些优势是创建像这样的大多数函数的充分理由。对于短列表,理解或标准列表创建(如上例所示)足以解决问题。

一个警告是,您可能必须根据应用程序的需要将结果打包到一个容器中。这是因为生成器会按需创建每个新条目,然后简单地流式传输结果:

def combinations(array,n):
    if n == 0:
        yield []
    else:
        for i in array:
            for j in combinations(array, n-1):
                yield j + [i]

>>> print(list(combinations(['aA','bB','cC'], 2)))
[['aA', 'aA'], ['bB', 'aA'], ['cC', 'aA'], ['aA', 'bB'], ['bB', 'bB'], ['cC', 'bB'], ['aA', 'cC'], ['bB', 'cC'], ['cC', 'cC']]

如果您想利用生成器的优点来理解,那么可以使用生成器理解(用( )代替[ ])和yield from语句:

def combs(a, n):
   if n == 0:
       yield []
   else:
       yield from (x + [y] for x in combs(a, n - 1) for y in a)

答案 1 :(得分:1)

Name