python 映射元组列表
python map over list of tuples
我有这样的元组列表:
rounds = [('R', 'S'), ('S', 'R'), ('S', 'R'), ('R', 'P'), ('S', 'S'),
('P', 'S'), ('P', 'S'), ('S', 'P'), ('R', 'R'), ('R', 'S')]
正在模拟RPS游戏
我也有这样的功能:
def RPS_winner(weapon1, weapon2):
if weapon1 == weapon2:
return 0
elif (weapon1, weapon2) in [('R', 'S'), ('P', 'S'), ('P', 'S')]:
return 1
else:
return 2
我如何使用 map() 得出这 10 轮的获胜者名单?
我知道是这样开始的:list(map(RPS_winner, ....)
你可以这样做:
winners = list(map(lambda x: RPS_winner(*x), rounds))
你不需要 map
这样的东西,实际上可以通过使用列表理解来提高可读性:
>>> [RPS_winner(a, b) for a, b in rounds]
[1, 2, 2, 2, 0, 1, 1, 2, 0, 1]
另一种可能性是使用 itertools.starmap
,它正是为此而设计的:
from itertools import starmap
list(starmap(RPS_winner, rounds))
当然,您也可以手动完成同样的操作:
list(map(lambda ab: RPS_winner(*ab), rounds)
如果您打算在非常长的 rounds
列表中使用,将其重写为:
def RPS_winner_star(ab):
return RPS_winner(*ab)
list(map(RPS_winner_star, rounds))
备注
请求使用 map
等的正当理由是 rounds
实际上不是列表而是另一个迭代器。在那种情况下,获得一个新的迭代器是很好的,该迭代器可以随着 rounds
的进行而吐出获胜者,而无需列出列表。例如,您可以将生成的迭代器“管道化”为 Counter
:
irounds = generate_rounds(n=1_000_000) # a generator
iwinner = map(RPS_winner_star, irounds)
score_board = Counter(iwinner)
这是一个完整的例子和时间安排:
(注意:generate_rounds
生成器现在可预测地重复,以努力减少其自身在整体测量中的时间;我们现在还减去花费在生成器在最后的时间比较中)。
import random
from collections import Counter
from itertools import starmap
def generate_rounds(n):
choices = list('RPS')
m = len(choices)
for k in range(n):
i = k % m
j = (k // m) % m
yield choices[i], choices[j]
def f_onlygen(n):
for _ in generate_rounds(n):
pass
def f_map(n):
irounds = generate_rounds(n) # a generator
iwinner = map(RPS_winner_star, irounds)
return Counter(iwinner)
def f_starmap(n):
irounds = generate_rounds(n) # a generator
iwinner = starmap(RPS_winner, irounds)
return Counter(iwinner)
def f_listmap(n):
rounds = list(generate_rounds(n))
winner = list(map(RPS_winner_star, rounds))
return Counter(winner)
def f_listcomprehension(n):
rounds = list(generate_rounds(n))
winner = [RPS_winner(a, b) for a, b in rounds]
return Counter(winner)
def f_comprehension(n):
irounds = generate_rounds(n)
winner = [RPS_winner(a, b) for a, b in rounds]
return Counter(winner)
测量值:
n = 1_000_000
t = {}
t['onlygen'] = %timeit -o f_onlygen(n)
t['map'] = %timeit -o f_map(n)
t['starmap'] = %timeit -o f_starmap(n)
t['listmap'] = %timeit -o f_listmap(n)
t['listcomprehension'] = %timeit -o f_listcomprehension(n)
t['comprehension'] = %timeit -o f_comprehension(n)
结果:
res = sorted([
(k, v.average, v.average - t['onlygen'].average)
for k, v in t.items()
], key=lambda tup: tup[2])
print(f'{"name":<17} {"total":<6} above onlygen')
for name, tot, rel in res:
print(f'{name:<17} {tot*1000:3.0f} ms, {rel*1000:3.0f} ms')
name total above onlygen
onlygen 172 ms, 0 ms
comprehension 235 ms, 62 ms
starmap 376 ms, 204 ms
map 432 ms, 260 ms
listcomprehension 470 ms, 298 ms
listmap 482 ms, 310 ms
Itertools 为此提供 starmap
。
from itertools import starmap
rounds = [('R', 'S'), ('S', 'R'), ('S', 'R'), ('R', 'P'), ('S', 'S'),
('P', 'S'), ('P', 'S'), ('S', 'P'), ('R', 'R'), ('R', 'S')]
def RPS_winner(weapon1, weapon2):
if weapon1 == weapon2:
return 0
elif (weapon1, weapon2) in [('R', 'S'), ('P', 'S'), ('P', 'S')]:
return 1
else:
return 2
list(starmap(RPS_winner, rounds))
# [1, 2, 2, 2, 0, 1, 1, 2, 0, 1]
starting like this: list(map(RPS_winner, ....)
如果这样开始,大概应该这样结束:
list(map(RPS_winner, *zip(*rounds)))
这给出了 map
三个参数:函数、玩家 1 的选择、玩家 2 的选择。
我有这样的元组列表:
rounds = [('R', 'S'), ('S', 'R'), ('S', 'R'), ('R', 'P'), ('S', 'S'),
('P', 'S'), ('P', 'S'), ('S', 'P'), ('R', 'R'), ('R', 'S')]
正在模拟RPS游戏 我也有这样的功能:
def RPS_winner(weapon1, weapon2):
if weapon1 == weapon2:
return 0
elif (weapon1, weapon2) in [('R', 'S'), ('P', 'S'), ('P', 'S')]:
return 1
else:
return 2
我如何使用 map() 得出这 10 轮的获胜者名单? 我知道是这样开始的:list(map(RPS_winner, ....)
你可以这样做:
winners = list(map(lambda x: RPS_winner(*x), rounds))
你不需要 map
这样的东西,实际上可以通过使用列表理解来提高可读性:
>>> [RPS_winner(a, b) for a, b in rounds]
[1, 2, 2, 2, 0, 1, 1, 2, 0, 1]
另一种可能性是使用 itertools.starmap
,它正是为此而设计的:
from itertools import starmap
list(starmap(RPS_winner, rounds))
当然,您也可以手动完成同样的操作:
list(map(lambda ab: RPS_winner(*ab), rounds)
如果您打算在非常长的 rounds
列表中使用,将其重写为:
def RPS_winner_star(ab):
return RPS_winner(*ab)
list(map(RPS_winner_star, rounds))
备注
请求使用 map
等的正当理由是 rounds
实际上不是列表而是另一个迭代器。在那种情况下,获得一个新的迭代器是很好的,该迭代器可以随着 rounds
的进行而吐出获胜者,而无需列出列表。例如,您可以将生成的迭代器“管道化”为 Counter
:
irounds = generate_rounds(n=1_000_000) # a generator
iwinner = map(RPS_winner_star, irounds)
score_board = Counter(iwinner)
这是一个完整的例子和时间安排:
(注意:generate_rounds
生成器现在可预测地重复,以努力减少其自身在整体测量中的时间;我们现在还减去花费在生成器在最后的时间比较中)。
import random
from collections import Counter
from itertools import starmap
def generate_rounds(n):
choices = list('RPS')
m = len(choices)
for k in range(n):
i = k % m
j = (k // m) % m
yield choices[i], choices[j]
def f_onlygen(n):
for _ in generate_rounds(n):
pass
def f_map(n):
irounds = generate_rounds(n) # a generator
iwinner = map(RPS_winner_star, irounds)
return Counter(iwinner)
def f_starmap(n):
irounds = generate_rounds(n) # a generator
iwinner = starmap(RPS_winner, irounds)
return Counter(iwinner)
def f_listmap(n):
rounds = list(generate_rounds(n))
winner = list(map(RPS_winner_star, rounds))
return Counter(winner)
def f_listcomprehension(n):
rounds = list(generate_rounds(n))
winner = [RPS_winner(a, b) for a, b in rounds]
return Counter(winner)
def f_comprehension(n):
irounds = generate_rounds(n)
winner = [RPS_winner(a, b) for a, b in rounds]
return Counter(winner)
测量值:
n = 1_000_000
t = {}
t['onlygen'] = %timeit -o f_onlygen(n)
t['map'] = %timeit -o f_map(n)
t['starmap'] = %timeit -o f_starmap(n)
t['listmap'] = %timeit -o f_listmap(n)
t['listcomprehension'] = %timeit -o f_listcomprehension(n)
t['comprehension'] = %timeit -o f_comprehension(n)
结果:
res = sorted([
(k, v.average, v.average - t['onlygen'].average)
for k, v in t.items()
], key=lambda tup: tup[2])
print(f'{"name":<17} {"total":<6} above onlygen')
for name, tot, rel in res:
print(f'{name:<17} {tot*1000:3.0f} ms, {rel*1000:3.0f} ms')
name total above onlygen
onlygen 172 ms, 0 ms
comprehension 235 ms, 62 ms
starmap 376 ms, 204 ms
map 432 ms, 260 ms
listcomprehension 470 ms, 298 ms
listmap 482 ms, 310 ms
Itertools 为此提供 starmap
。
from itertools import starmap
rounds = [('R', 'S'), ('S', 'R'), ('S', 'R'), ('R', 'P'), ('S', 'S'),
('P', 'S'), ('P', 'S'), ('S', 'P'), ('R', 'R'), ('R', 'S')]
def RPS_winner(weapon1, weapon2):
if weapon1 == weapon2:
return 0
elif (weapon1, weapon2) in [('R', 'S'), ('P', 'S'), ('P', 'S')]:
return 1
else:
return 2
list(starmap(RPS_winner, rounds))
# [1, 2, 2, 2, 0, 1, 1, 2, 0, 1]
starting like this: list(map(RPS_winner, ....)
如果这样开始,大概应该这样结束:
list(map(RPS_winner, *zip(*rounds)))
这给出了 map
三个参数:函数、玩家 1 的选择、玩家 2 的选择。