开发者

Positional Comparisons in Python

开发者 https://www.devze.com 2022-12-20 23:55 出处:网络
(Here\'s a sort of hypothetical situation for everybody. I\'m more looking for directions rather than straight processes, but if you can provide them, awesome!)

(Here's a sort of hypothetical situation for everybody. I'm more looking for directions rather than straight processes, but if you can provide them, awesome!)

So let's say we have a list of athletes, I'm going to use figure skaters since I'm knee deep in the Winter Olympics right now. (I'm throwing it in a dictionary since that's my first instinct, doesn't have to be this way.)

after_short_program = {
    '1': 'Evgeni Plushenko',
    '2': 'Evan Lysacek',
    '3': 'Daisuke Takahashi',
    '4': 'Nobunari Oda',
    '5': 'Stephane Lambiel'
}

So after the free skate (which hasn't happened as I ask this), let's say these are the standings.

after_free_skate = {
    '1': 'Evan Lysacek',
    '2': 'Daisuke Takahashi',
    '3': 'Evgeni Plushenko',
    '4': 'Stephane Lambiel',
    '5': 'Nobunari Oda',
}

So, the questions:

How would one go about comparing the two sets of data? Evan Lysacek moved up one space to win the gold, Daisuke moved up one place to win the silver and Evgeni moved down two spaces to win the bron开发者_开发技巧ze. Off the top of my head, if I were to render this information, I'd want to say, "Evan (+1 or moved up one), Evgeni (-2 or moved down two), etc."

Is there a way in Python to extract that sort of data from comparisons?


I would use the athlet name as key in your dicts. Then you can look for their position more easily. Something like:

diff = {}
for (a, pos2) in after_free_skate.items():
     pos1 = after_short_program[a]
     diff[a] = pos2 - pos1

I hope it helps


This solution prints the results in the same order as the final placings.
If the place has not changed (+0) is printed.
If you wish to filter those out instead, simply put an if diff: before the print

>>> after_short_program = [
...     'Evgeni Plushenko',
...     'Evan Lysacek',
...     'Daisuke Takahashi',
...     'Nobunari Oda',
...     'Stephane Lambiel',
... ]
>>> 
>>> after_free_skate = [
...     'Evan Lysacek',
...     'Daisuke Takahashi',
...     'Evgeni Plushenko',
...     'Stephane Lambiel',
...     'Nobunari Oda',
... ]
>>> 
>>> for i,item in enumerate(after_free_skate):
...     diff = after_short_program.index(item)-i
...     print "%s (%+d)"%(item,diff)
...     
... 
Evan Lysacek (+1)
Daisuke Takahashi (+1)
Evgeni Plushenko (-2)
Stephane Lambiel (+1)
Nobunari Oda (-1)

As pwdyson points out, if your stopwatches aren't good enough, you might get a tie. So this modification uses dicts instead of lists. The order of the placings is still preserved

>>> from operator import itemgetter
>>> 
>>> after_short_program = {
...     'Evgeni Plushenko':1,
...     'Evan Lysacek':2,
...     'Daisuke Takahashi':3,
...     'Stephane Lambiel':4,
...     'Nobunari Oda':5,
... }
>>> 
>>> after_free_skate = {
...     'Evan Lysacek':1,
...     'Daisuke Takahashi':2,
...     'Evgeni Plushenko':3,
...     'Stephane Lambiel':4,   # These are tied
...     'Nobunari Oda':4,       # at 4th place
... }
>>> 
>>> for k,v in sorted(after_free_skate.items(),key=itemgetter(1)):
...     diff = after_short_program[k]-v
...     print "%s (%+d)"%(k,diff)
...     
... 
Evan Lysacek (+1)
Daisuke Takahashi (+1)
Evgeni Plushenko (-2)
Nobunari Oda (+1)
Stephane Lambiel (+0)
>>> 

If there is a possibility of keys in the second dict that are not in the first you can do something like this

for k,v in sorted(after_free_skate.items(),key=itemgetter(1)):
    try:
        diff = after_short_program[k]-v
        print "%s (%+d)"%(k,diff)
    except KeyError:
        print "%s (new)"%k


One way would be to flip the keys and values, then take the difference, ie:

for k, v in after_free_skate.items():
   print 'k', v - after_short_program[k]  


I'd personally use lists as they are naturally suited to store 'positional' information... the following is a rather functional approach employing lists:

###_* input data
after_short_program = [
    'Evgeni Plushenko',
    'Evan Lysacek',
    'Daisuke Takahashi',
    'Nobunari Oda',
    'Stephane Lambiel'
    ]
after_free_skate = [
    'Evan Lysacek',
    'Daisuke Takahashi',
    'Evgeni Plushenko',
    'Stephane Lambiel',
    'Nobunari Oda'
    ]

## combine
all_athletes = set(after_short_program + after_free_skate)

###_* import libraries, define functions
from operator import add, sub
from functools import partial

def tryit(f,*args):
    try: return f(*args)
    except: return None
def compose(f,g): ## available in functional library
    return lambda x: f(g(x))

###_* apply functions
## original and new positions for each athlete
## I usually wrap list.index() in a try-except clause
pos = [(x,{'orig':tryit(compose(partial(add,1),after_short_program.index),x),
           'new':tryit(compose(partial(add,1),after_free_skate.index),x)})
       for i,x in enumerate(all_athletes)]

## calculate the changes (now edited to sort by final position)
changes = [(x[0],tryit(sub,x[1]['orig'],x[1]['new']))
           for x in sorted(pos,key=lambda x: x[1]['new'])]

The output is as follows:

>>> changes
[('Evan Lysacek', 1), ('Daisuke Takahashi', 1), ('Evgeni Plushenko', -2), ('Stephane Lambiel', 1), ('Nobunari Oda', -1)]


I would put the names as keys and the positions as values, with the positions as ints:

after_short_program = {
    '1': 'Evgeni Plushenko',
    '2': 'Evan Lysacek',
    '3': 'Daisuke Takahashi',
    '4': 'Nobunari Oda',
    '5': 'Stephane Lambiel'
}

after_free_skate = {
    '1': 'Evan Lysacek',
    '2': 'Daisuke Takahashi',
    '3': 'Evgeni Plushenko',
    '4': 'Stephane Lambiel',
    '5': 'Nobunari Oda',
}

after_short_program_swap = {}
for k,v in after_short_program.iteritems():
   after_short_program_swap[v]=int(k)

after_free_skate_swap = {}
for k,v in after_free_skate.iteritems():
    after_free_skate_swap[v]=int(k)

then the code is much simpler:

moved = {}
for key in after_short_program_swap:
    moved[key] = after_short_program_swap[key] - after_free_skate_swap[key]

print moved

prints:

{'Evan Lysacek': 1, 'Nobunari Oda': -1, 'Evgeni Plushenko': -2, 'Stephane Lambiel': 1, 'Daisuke Takahashi': 1}

to print out in the medal order, following @gnibbler:

from operator import itemgetter
print '\n'.join('%s (%+d)' % (k,moved[k]) for k,v in sorted(after_free_skate_swap.items(),key=itemgetter(1)))

Evan Lysacek (+1)

Daisuke Takahashi (+1)

Evgeni Plushenko (-2)

Stephane Lambiel (+1)

Nobunari Oda (-1)

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号