递归拆分列表直到平坦

Bal*_*ter 21 python

我正在编写一个激情程序,它将确定给定底牌和公共牌的最佳扑克手。由于 A 可以在顺子中双向进行,因此对于给定的 5 张牌组合,我将其编码为 [1, 14]。

我理解递归,但实现它对我来说是另一回事。我正在寻找一个函数,它将递归地将所有 ace 拆分为所有可能的手牌组合,直到所有嵌套列表都用完为止。这显然应该与最多 4 个 A 一起使用,忽略了你很可能不会在意顺子的事实。

hand = [[1, 14], 2, 3, [1, 14], 7]

desired_output = [
        [1, 2, 3, 1, 7],
        [1, 2, 3, 14, 7],
        [14, 2, 3, 1, 7],
        [14, 2, 3, 14, 7]
        ]
Run Code Online (Sandbox Code Playgroud)

我对到目前为止所拥有的东西并不感到自豪,特别是因为它返回一个列表,而不是像 ayield这样的东西,它会构建我正在寻找的列表:

def split_first_ace(hand):
    aces = [True if isinstance(x, list) else False for x in hand]
    for i, x in enumerate(aces):
        if x:
            ranks_temp = hand.copy()
            ace = ranks_temp.pop(i)
            return [[ace[0]] + ranks_temp, [ace[1]] + ranks_temp]
Run Code Online (Sandbox Code Playgroud)

对解决方案的任何帮助将不胜感激,主要是因为它会帮助我了解如何实现递归。但我也愿意接受其他解决方案。

Mar*_*rat 20

好吧,有一种更简单的方法可以做到这一点:

from itertools import product

product(*[i if isinstance(i, list) else [i] for i in hand])
Run Code Online (Sandbox Code Playgroud)

我挑战每个人想出一个更简单的解决方案

  • “from collections.abc import Iterable”然后“isinstance(i, Iterable)”不是更好吗?(或者相同,用 `Sequence` 代替。)并且,如果您想要一些_过早优化_,您可能应该编写 `*(...)` 而不是 `*[...]` 以避免不必要的创建列表(有关详细信息,请参阅“dis.dis()”——不过,它是一个额外的字节码指令;您需要一个额外的“POP_TOP”,因为“YIELD_VALUE”返回“None”)。(实际上,您可以将 `[i]` 替换为 `(i,)`,尽管我不确定这是否会有什么作用。) (2认同)

Aar*_*ing 10

itertools.product()功能可能有用。如果我们假设递归只有 1 级深(ace 本身没有嵌套列表),那么我们可以使用以下内容:

from itertools import product

hand = [[1, 14], 2, 3, [1, 14], 7]

aces = [x for x in hand if isinstance(x, list)]
rest = [x for x in hand if isinstance(x, int)]

combinations = [list(x) + rest for x in product(*aces)]
print(combinations)
Run Code Online (Sandbox Code Playgroud)

产量:

[[1, 1, 2, 3, 7], [1, 14, 2, 3, 7], [14, 1, 2, 3, 7], [14, 14, 2, 3, 7]]
Run Code Online (Sandbox Code Playgroud)