如何用Python列表推导式创建多副扑克牌的合并扁平列表?
问题描述
我定义了如下Card类:
class Card: def __init__(self, rank, suit, d=0): self.rank = rank self.suit = suit self.deck_index = d
通过列表推导式可以生成单副标准扑克牌的Card对象列表:
ranks = [2, 3, 4, 5, 6, 7, 8, 9, 10, 'J', 'Q', 'K', 'A'] suits = ['hearts', 'clubs', 'diamonds', 'spades'] deck = ([Card(r, s) for r in ranks for s in suits] + [Card('Joker', 'black'), Card('Joker', 'red')])
现在需要用列表推导式生成N副合并后的扁平Card对象列表。用for循环可以实现需求:
decks = [] for i in range(N): decks += ([Card(r, s, d=i) for r in ranks for s in suits] + [Card('Joker', 'black', i), Card('Joker', 'red', i)])
但直接转成列表推导式会得到嵌套列表(列表的列表),而非扁平的Card对象列表:
decks = [[Card(r, s, d=i) for r in ranks for s in suits] + [Card('Joker', 'black', i), Card('Joker', 'red', i)] for i in range(N)]
尝试用*解包会触发错误:Iterable unpacking cannot be used in comprehension。
如果分开推导普通牌组和大小王再合并,不仅会重复循环,还无法保留每副牌自带大小王的顺序:
decks = ([Card(r, s, i) for r in ranks for s in suits for i in range(N)] + [Card('Joker', 'black', i) for i in range(N)] + [Card('Joker', 'red', i) for i in range(N)])
通用问题
已知lst = lst1 + lst2是元素列表,lsts = [lst1(i) + lst2(i) for i in range(N)]是嵌套列表,如何用列表推导式直接生成包含所有lst1(i) + lst2(i)元素的扁平列表?(不想先生成嵌套列表再做扁平化处理)
解决方案
方法1:嵌套循环的列表推导式(直接生成扁平列表)
在列表推导式中通过多层循环,直接遍历每个牌组的所有元素,避免生成中间嵌套列表:
decks = [ card for i in range(N) for card in ([Card(r, s, d=i) for r in ranks for s in suits] + [Card('Joker', 'black', i), Card('Joker', 'red', i)]) ]
如果想要更清晰的层级,可以拆分普通牌和大小王的遍历逻辑:
decks = [ card for i in range(N) # 遍历当前副牌的所有普通牌 for r in ranks for s in suits for card in [Card(r, s, d=i)] # 遍历当前副牌的大小王 for card in [Card('Joker', 'black', i), Card('Joker', 'red', i)] ]
方法2:借助itertools.chain实现扁平化
使用itertools.chain.from_iterable直接拼接每个牌组的元素序列,无需生成嵌套列表:
from itertools import chain decks = list(chain.from_iterable( ([Card(r, s, d=i) for r in ranks for s in suits] + [Card('Joker', 'black', i), Card('Joker', 'red', i)]) for i in range(N) ))
如果想减少内存开销,可以用生成器表达式替代内层列表推导式:
from itertools import chain def generate_single_deck(deck_idx): # 生成普通牌 for rank in ranks: for suit in suits: yield Card(rank, suit, d=deck_idx) # 生成大小王 yield Card('Joker', 'black', deck_idx) yield Card('Joker', 'red', deck_idx) decks = list(chain.from_iterable(generate_single_deck(i) for i in range(N)))
方法3:合并元素生成逻辑到同一层级
把每个牌组的普通牌和大小王合并到同一个推导循环里,通过预先构造元素元组保证顺序:
decks = [ Card(rank, suit, d=i) for i in range(N) for rank, suit in [(r, s) for r in ranks for s in suits] + [('Joker', 'black'), ('Joker', 'red')] ]
内容的提问来源于stack exchange,提问作者WeCanDoItGuys
相关产品推荐
相关产品推荐

