我正在寻找一个优雅(快速)的python函数,它可以生成以下两个数组的每个组合。
cards = ["8H", "8S", "8C", "8D", "9H", "9S", "9C", "9D", "10H", "10S", "10C", "10D", "AH", "AS", "AC", "AD"]
players = ["_1", "_1", "_1", "_2", "_2", "_2", "_3", "_3", "_3", "_4", "_4", "_4", "_To", "_To", "_To", "_Tc"]
组合看起来像:
[('8H', '_1'), ('8S', '_1'), ('8C', '_1'), ('8D', '_2'), ('9H', '_2'), ('9S', '_2'), ('9C', '_3'), ('9D', '_3'), ('10H', '_3'), ('10S', '_4'), ('10C', '_4'), ('10D', '_4'), ('AH', '_To'), ('AS', '_To'), ('AC', '_To'), ('AD', '_Tc')]
但是!没有平等,我的意思是什么。 例如:
如果卡片是:
["a", "b", "c", "d"]
如果玩家是:
["1", "1", "2", "2"]
结果:
[1a, 1b, 2c, 2d]
[1a, 1c, 2b, 2d]
[1a, 1d, 2b, 2c]
[1b, 1c, 2a, 2d]
[1b, 1d, 2a, 2c]
[1c, 1d, 2a, 2b]
不是例如:
[1a, 1b, 2d, 2c]
具有(c和d)的玩家2等于(d和c)
我尝试了itertools
的功能,例如combinations
和permutations
,但没有运气。由于状态空间爆炸,在所有组合之后拒绝等于并不是真正的选择。
我希望有人有解决方案,因为Google搜索此特定问题失败了。
答案 0 :(得分:3)
我建议使用递归算法。
我正在使用生成器来使代码在恒定空间中运行,并且尽快开始生成结果,而不是最后的巨大结果;如果您之前没有听说过发电机,请参见http://www.dabeaz.com/generators/。
作为旁注,我建议使用标准化数据结构来保存您的玩家列表和手牌大小,以便根本不需要groupby
的行...在任何情况下,默认/大部分时间保持数据规范化通常是一个好主意,并且只使用非规范化/扁平化形式,例如对于某些可能需要或运行速度更快的平面结构算法。
这是代码;随意提出清理/简化:
from itertools import combinations, groupby, islice
cards = ["a", "b", "c", "d"]
players = ["1", "1", "2", "2"]
def hand_combinations(players, cards):
# convert ["1", "1", "2", "2"] into [("1", 2), ("2", 2)]
players = list((x, len(list(y))) for x, y in groupby(players))
# sets are faster to operate on in our case
cards = set(cards)
def generate(players, cards):
if not players:
yield []
else:
# pick the first player
player_name, player_hand_size = players[0]
# and then walk over all the possible hands for this player
for player_hand in combinations(cards, player_hand_size):
# for each hand, use the cards that are left to build all the
# possible hands for the rest of the players in this iteration
for tail in generate(players[1:], cards - set(player_hand)):
yield [(player_name, player_hand)] + tail
return generate(players, cards)
# take only the 100 first combinations; otherwise it'll take
# forever with the larger example
combos = islice(hand_combinations(players, cards), 0, 100)
# convert back to the flat structure
flattened = [
' '.join(
player_name + ':' + card
for player_name, player_cards in combo
for card in player_cards
)
for combo in combos
]
from pprint import pprint
pprint(flattened)
<强>输出:强>
['1:a 1:c 2:b 2:d',
'1:a 1:b 2:c 2:d',
'1:a 1:d 2:c 2:b',
'1:c 1:b 2:a 2:d',
'1:c 1:d 2:a 2:b',
'1:b 1:d 2:a 2:c']
或与更大的考官一起:
['_1:AS _1:9H _1:8H _2:AC _2:10H _2:AD _3:10S _3:10C _3:9C _4:8C _4:9D _4:8D _To:AH _To:9S _To:10D _Tc:8S',
'_1:AS _1:9H _1:8H _2:AC _2:10H _2:AD _3:10S _3:10C _3:9C _4:8C _4:9D _4:8D _To:AH _To:9S _To:8S _Tc:10D',
'_1:AS _1:9H _1:8H _2:AC _2:10H _2:AD _3:10S _3:10C _3:9C _4:8C _4:9D _4:8D _To:AH _To:10D _To:8S _Tc:9S',
'_1:AS _1:9H _1:8H _2:AC _2:10H _2:AD _3:10S _3:10C _3:9C _4:8C _4:9D _4:8D _To:9S _To:10D _To:8S _Tc:AH',
'_1:AS _1:9H _1:8H _2:AC _2:10H _2:AD _3:10S _3:10C _3:9C _4:8C _4:9D _4:10D _To:AH _To:9S _To:8D _Tc:8S',
'_1:AS _1:9H _1:8H _2:AC _2:10H _2:AD _3:10S _3:10C _3:9C _4:8C _4:9D _4:10D _To:AH _To:9S _To:8S _Tc:8D',
'_1:AS _1:9H _1:8H _2:AC _2:10H _2:AD _3:10S _3:10C _3:9C _4:8C _4:9D _4:10D _To:AH _To:8D _To:8S _Tc:9S',
'_1:AS _1:9H _1:8H _2:AC _2:10H _2:AD _3:10S _3:10C _3:9C _4:8C _4:9D _4:10D _To:9S _To:8D _To:8S _Tc:AH',
'_1:AS _1:9H _1:8H _2:AC _2:10H _2:AD _3:10S _3:10C _3:9C _4:8C _4:9D _4:AH _To:8S _To:9S _To:10D _Tc:8D',
'_1:AS _1:9H _1:8H _2:AC _2:10H _2:AD _3:10S _3:10C _3:9C _4:8C _4:9D _4:AH _To:8S _To:9S _To:8D _Tc:10D',
'_1:AS _1:9H _1:8H _2:AC _2:10H _2:AD _3:10S _3:10C _3:9C _4:8C _4:9D _4:AH _To:8S _To:10D _To:8D _Tc:9S',
'_1:AS _1:9H _1:8H _2:AC _2:10H _2:AD _3:10S _3:10C _3:9C _4:8C _4:9D _4:AH _To:9S _To:10D _To:8D _Tc:8S',
...
答案 1 :(得分:1)
好的,你真正想要的是:
set(tuple(zip(p, players)) for p in it.permutations(cards))
但这需要花费太多时间。所以,试试吧。
cards = set(["8H", "8S", "8C", "8D", "9H", "9S", "9C", "9D", "10H", "10S", "10C", "10D", "AH", "AS", "AC", "AD"])
def deals(cards, players, cards_per_player):
if not cards:
yield []
return
for hand in it.combinations(cards, cards_per_player[0]):
hand = set(hand)
for deal in deals(cards - hand, players[1:], cards_per_player[1:]):
yield zip([players[0]]*len(hand), hand) + deal
> for deal in deals(cards, ['_1', '_2', '_3', '_4', '_Tc', '_To'], [3,3,3,3,1,3]):
print deal
这还需要很长时间,但处理这些卡的方法很多。
答案 2 :(得分:0)
你可以每人使用一系列卡片,并按顺序放置卡片,所以当你匹配这两个阵列时,它们将是相同的。 您可以为每张卡使用元组(大小为2),其中第一个元素可以表示范围(13)中的值,第二个元素可以是颜色(也用范围(4)中的数字表示)。您可以轻松生成带有双循环的套牌,也许作为字典,在处理完卡片后,您可以删除已经使用过的卡片,这样就不会有重复,并且当您处理所有的手牌时(如果有的话)代码很容易修改它以拥有不同数量的玩家)你可以订购手,将它与你已经拥有的数据库进行比较,如果有匹配则不保存它,你也可以保存如果你想要的话,你可以做一些统计数据的剩余部分,而不是你可以为每种情况进行所有可能的交易,无论如何都是一个庞大的数据库。通过这种方式,您将拥有所有可能性,手中或玩家手中没有重复。 (玩家一方在不同的交易中拥有玩家二的手,反之亦然) 我希望这对你或其他人有所帮助。 我没有提供代码示例,因为这个问题更像是如何解决这个问题,其他人给了你编码提示。即使你刚刚启动python并且直到现在才做了一些教程,这种方法也可以完成。 祝你好运;)