Home > front end >  python map over list of tuples
python map over list of tuples

Time:12-31

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))
  • Related