1

(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 bronze. 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?

5 Answers 5

7

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

Sign up to request clarification or add additional context in comments.

Comments

3

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

4 Comments

Sorry, I was unclear. I meant it can't deal with two people being tied in their standing after an event. This is not mentioned in the question, though.
@pwdyson, ok I added a version using dicts for the placings
In the end I preferred this way of going about things. Thank you so much. :) If you do see this, I'm wondering if you could expand on your answer, showing how you'd handle new items in the 2nd list.
@Bryan Veloso, sure I added one way to do it to the bottom of my answer
1

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]  

1 Comment

That should be after_free_skate.items():
1

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)]

2 Comments

While I like how this guards against having different elements, it doesn't sort them in "medal order" like the rest of the solutions.
Thank you. But sorting by place order is not difficult - please see application of sorted() function above!
0

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)

1 Comment

This doesn't print the places in any particular order. I thought it should be in the order of gold,silver,bronze,4th,5th etc.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.