Python 递归地拆分列表,直到平铺
我正在写一个激情计划,将决定最好的扑克手给洞卡和社区卡。由于a可以在直线上双向移动,对于给定的5张牌组合,我将其编码为[1,14] 我理解递归,但实现它对我来说是另一回事。我正在寻找一个函数,它可以递归地将所有ACE拆分为所有可能的手动组合,直到所有嵌套列表都用完为止。很明显,这应该适用于最多4个a,忽略了这样一个事实,即在这一点上,你很可能不在乎一个直道Python 递归地拆分列表,直到平铺,python,Python,我正在写一个激情计划,将决定最好的扑克手给洞卡和社区卡。由于a可以在直线上双向移动,对于给定的5张牌组合,我将其编码为[1,14] 我理解递归,但实现它对我来说是另一回事。我正在寻找一个函数,它可以递归地将所有ACE拆分为所有可能的手动组合,直到所有嵌套列表都用完为止。很明显,这应该适用于最多4个a,忽略了这样一个事实,即在这一点上,你很可能不在乎一个直道 hand = [[1, 14], 2, 3, [1, 14], 7] desired_output = [ [1, 2,
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]
]
到目前为止,我并不为我所拥有的感到自豪,特别是因为它返回的是一个列表,而不是像yield
这样的东西,它将构建我正在寻找的列表:
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]
任何关于解决方案的帮助都将不胜感激,因为这将帮助我理解如何实现递归。但是我也对其他解决方案持开放态度。itertools.product()函数可能很有用。如果我们假设递归只有1级深度(ACE本身没有嵌套列表),那么我们可以使用以下方法: 来自itertools导入产品的
手=[[1,14],2,3,[1,14],7]
aces=[x代表手上的x,如果存在(x,列表)]
rest=[x表示手上的x,如果存在(x,int)]
组合=[列表(x)+产品中x的剩余(*aces)]
印刷品(组合)
收益率:
[[1,1,2,3,7]、[1,14,2,3,7]、[14,1,2,3,7]、[14,14,2,3,7]]
这可能有些过分,因为您只需要一个级别的递归(如@Aaron Keesing的答案),但这应该是可行的:
def iter_hands(hand, __current_index=0, __current_combo=None):
__current_combo = __current_combo or []
if __current_index == len(hand):
yield __current_combo.copy()
return
choices = hand[__current_index]
if not isinstance(choices, list):
choices = [choices]
for c in choices:
__current_combo.append(c)
yield from iter_hands(hand, __current_index + 1, __current_combo)
__current_combo.pop()
def main():
input_hand = [[1, 14], 2, 3, [1, 14], 7]
want_hands = [
[1, 2, 3, 1, 7],
[1, 2, 3, 14, 7],
[14, 2, 3, 1, 7],
[14, 2, 3, 14, 7]
]
got_hands = [hand for hand in iter_hands(input_hand)]
assert want_hands == got_hands
if __name__ == '__main__':
main()
嗯,有一种更简单的方法:
from itertools import product
product(*[i if isinstance(i, list) else [i] for i in hand])
我要求大家拿出一个更简单的解决方案只要一点反馈,您就可以用包含ace的索引列表替换
True
/False
列表(如图所示)。简言之,如果x==[1,14],索引=[i代表i,x在enumerate(hand)中为x=[1,14]]
。现在,您只需迭代索引
,而不用枚举ACE
并检查它是否为真
@JolonB是的,您是对的。我可以省下一点冗员。感谢您的反馈。我会声称,为了清晰起见,我一直在对该部分进行编码;)由于您的输出将是一个手的列表。。。从一开始就这样定义手可能是个好主意,hand=[[1,14],2,3,[1,14],7]
@RichieV我确实会用这种方式定义手,因为我将迭代所有可能的手组合列表,以确定手是直的,还是齐平的,或者你有什么。我花了一段时间才明白,您正在将每张卡片都放入一个列表,这就是为什么产品(*
有效…不会从集合中导入。abc导入Iterable
,然后isinstance(i,Iterable)
会更好吗?(或者同样,使用序列
)而且,如果您想要一些过早的优化,您可能应该编写*(…)
,而不是*[…]
,以避免不必要的列表创建(请参见dis.dis()
了解详细信息–这是一条额外的字节码指令;但是,您需要一条额外的POP\u TOP
,因为产生的值返回无。(实际上,您可以用(i,)
替换[i]
,尽管我不确定这是否有什么作用。)@WIZWIZZ4您所有的建议都是正确的。检查Iterable
将使这一点更一般,使用生成器表达式和元组将减少内存占用。但是,考虑到数据量,预期效果将很小。不过,我承认,这是一个“足够好”的方法在解决方案和生产中,最好坚持您指定的最佳实践。