I have list of tuples like this:
rounds = [('R', 'S'), ('S', 'R'), ('S', 'R'), ('R', 'P'), ('S', 'S'),
('P', 'S'), ('P', 'S'), ('S', 'P'), ('R', 'R'), ('R', 'S')]
that are simulating RPS game also i have a function like this:
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
how do i use map() to derive a list of the winners in those 10 rounds? i know is starting like this: list(map(RPS_winner, ....)
CodePudding user response:
Itertools provides starmap
for this.
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]
CodePudding user response:
You don't need map
for something like that, and in fact would gain readability by using a list comprehension:
>>> [RPS_winner(a, b) for a, b in rounds]
[1, 2, 2, 2, 0, 1, 1, 2, 0, 1]
Another possibility is to use itertools.starmap
, which is designed precisely for that:
from itertools import starmap
list(starmap(RPS_winner, rounds))
And, of course, you can do the same by hand:
list(map(lambda ab: RPS_winner(*ab), rounds)
which, if you intend to use on very long list of rounds
, would benefit being rewritten as:
def RPS_winner_star(ab):
return RPS_winner(*ab)
list(map(RPS_winner_star, rounds))
Note
A justifiable reason to request the use of map
or the like is that rounds
is in fact not a list but another iterator. In that case, it's nice to obtain a new iterator that spits out winners as rounds
go, without making lists. For example, you could then "pipe" that resulting iterator into a Counter
:
irounds = generate_rounds(n=1_000_000) # a generator
iwinner = map(RPS_winner_star, irounds)
score_board = Counter(iwinner)
Here is a full example:
import random
from collections import Counter
def generate_rounds(n):
for _ in range(n):
r = random.choice(list('RPS')), random.choice(list('RPS'))
yield r
%%time
irounds = generate_rounds(n=1_000_000) # a generator
iwinner = map(RPS_winner_star, irounds)
score_board = Counter(iwinner)
# CPU times: user 1.49 s, sys: 0 ns, total: 1.49 s
# Wall time: 1.49 s
%%time
rounds = list(generate_rounds(n=1_000_000))
winner = list(map(RPS_winner_star, rounds))
score_board = Counter(winner)
# CPU times: user 1.53 s, sys: 11.1 ms, total: 1.54 s
# Wall time: 1.54 s
%%time
rounds = list(generate_rounds(n=1_000_000))
winner = [RPS_winner(a, b) for a, b in rounds]
score_board = Counter(winner)
# CPU times: user 1.5 s, sys: 24.3 ms, total: 1.53 s
# Wall time: 1.53 s
As you can see, in this example the timing difference is small.
CodePudding user response:
You can do this:
winners = list(map(lambda x: RPS_winner(*x), rounds))