Finding attributes in a list

Discussion in 'Python' started by Ben, Mar 29, 2005.

  1. Ben

    Ben Guest

    Hi

    In a list I have a number of soccer players. Each player has a
    different rating for attacking, defending, midfield fitness and
    goalkeeping.

    I have devised a while loop that goes through this list to find the
    best player at defending, attacking, midfield and goalkeeping. However
    there is more than one defender per team so I therefore need it to find
    the next best player.

    Below is the code used to ascertain the best defender:


    # STUFF TO FIND THE TOP DEFENDER
    defender = 0 # The position of defender is set to the first player
    in the knowledge base
    topdefender = 0
    c = 3 # the defensive rating of the first player in the list
    d = (len(squadList)-4) # the defensive rating of the last player in the
    list.

    while c <= d:
    if squadList[c] > topdefender:
    topdefender = squadList[c]
    defender = squadList[c-3] + " " + squadList[c-2] # The
    defender variable is assigned to the forename and surname of the player
    c = c + 8 # Move to the defensive rating of the next player in the
    list

    print defender



    any help on this would be greatly appreciated.

    thank you
     
    Ben, Mar 29, 2005
    #1
    1. Advertising

  2. Ben

    infidel Guest

    You can use the new 'sorted' built-in function and custom "compare"
    functions to return lists of players sorted according to any criteria:

    >>> players = [

    .... {'name' : 'joe', 'defense' : 8, 'attacking' : 5, 'midfield' : 6,
    'goalkeeping' : 9},
    .... {'name' : 'bob', 'defense' : 5, 'attacking' : 9, 'midfield' : 6,
    'goalkeeping' : 3},
    .... {'name' : 'sam', 'defense' : 6, 'attacking' : 7, 'midfield' : 10,
    'goalkeeping' : 4}
    .... ]
    >>> def cmp_attacking(first, second):

    .... return cmp(second['attacking'], first['attacking'])
    ....
    >>> [p['name'] for p in sorted(players, cmp_attacking)]

    ['bob', 'sam', 'joe']
    >>>
     
    infidel, Mar 29, 2005
    #2
    1. Advertising

  3. infidel wrote:
    > You can use the new 'sorted' built-in function and custom "compare"
    > functions to return lists of players sorted according to any criteria:
    >
    >
    >>>>players = [

    >
    > ... {'name' : 'joe', 'defense' : 8, 'attacking' : 5, 'midfield' : 6,
    > 'goalkeeping' : 9},
    > ... {'name' : 'bob', 'defense' : 5, 'attacking' : 9, 'midfield' : 6,
    > 'goalkeeping' : 3},
    > ... {'name' : 'sam', 'defense' : 6, 'attacking' : 7, 'midfield' : 10,
    > 'goalkeeping' : 4}
    > ... ]
    >
    >>>>def cmp_attacking(first, second):

    >
    > ... return cmp(second['attacking'], first['attacking'])
    > ...
    >
    >>>>[p['name'] for p in sorted(players, cmp_attacking)]

    >
    > ['bob', 'sam', 'joe']


    Or more efficiently, use the key= and reverse= parameters:

    py> players = [
    .... dict(name='joe', defense=8, attacking=5, midfield=6),
    .... dict(name='bob', defense=5, attacking=9, midfield=6),
    .... dict(name='sam', defense=6, attacking=7, midfield=10)]
    py> import operator
    py> [p['name'] for p in sorted(players,
    .... key=operator.itemgetter('attacking'),
    .... reverse=True)]
    ['bob', 'sam', 'joe']

    STeVe
     
    Steven Bethard, Mar 29, 2005
    #3
  4. On Tue, 29 Mar 2005 11:29:33 -0700, Steven Bethard <> wrote:

    >infidel wrote:
    >> You can use the new 'sorted' built-in function and custom "compare"
    >> functions to return lists of players sorted according to any criteria:
    >>
    >>
    >>>>>players = [

    >>
    >> ... {'name' : 'joe', 'defense' : 8, 'attacking' : 5, 'midfield' : 6,
    >> 'goalkeeping' : 9},
    >> ... {'name' : 'bob', 'defense' : 5, 'attacking' : 9, 'midfield' : 6,
    >> 'goalkeeping' : 3},
    >> ... {'name' : 'sam', 'defense' : 6, 'attacking' : 7, 'midfield' : 10,
    >> 'goalkeeping' : 4}
    >> ... ]
    >>
    >>>>>def cmp_attacking(first, second):

    >>
    >> ... return cmp(second['attacking'], first['attacking'])
    >> ...
    >>
    >>>>>[p['name'] for p in sorted(players, cmp_attacking)]

    >>
    >> ['bob', 'sam', 'joe']

    >
    >Or more efficiently, use the key= and reverse= parameters:
    >
    >py> players = [
    >... dict(name='joe', defense=8, attacking=5, midfield=6),
    >... dict(name='bob', defense=5, attacking=9, midfield=6),
    >... dict(name='sam', defense=6, attacking=7, midfield=10)]
    >py> import operator
    >py> [p['name'] for p in sorted(players,
    >... key=operator.itemgetter('attacking'),
    >... reverse=True)]
    >['bob', 'sam', 'joe']
    >

    Perhaps the OP doesn't yet realize that Python also provides the ability
    to define custom classes to represent players etc. E.g., using instance attribute
    dicts instead of raw dicts (to save typing ;-):

    >>> class Player(object):

    ... def __init__(self, **kw): self.__dict__.update(kw)
    ... def __repr__(self): return '<Player %s>'%getattr(self, 'name', '(anonymous)')
    ...
    >>> players = [

    ... Player(name='joe', defense=8, attacking=5, midfield=6),
    ... Player(name='bob', defense=5, attacking=9, midfield=6),
    ... Player(name='sam', defense=6, attacking=7, midfield=10)]
    >>> players

    [<Player joe>, <Player bob>, <Player sam>]
    >>> import operator
    >>> [p.name for p in sorted(players, key=operator.attrgetter('attacking'), reverse=True)]

    ['bob', 'sam', 'joe']

    And then he could create a Team class which might have players as an internal list,
    and provide methods for modifying the team etc., and generating various reports
    or calculating and/or retrieving data. Not to mention properties for dynamically
    caclulated attributes etc ;-)

    Regards,
    Bengt Richter
     
    Bengt Richter, Mar 30, 2005
    #4
  5. > class Player(object):
    > def __init__(self, **kw): self.__dict__.update(kw)
    > def __repr__(self): return '<Player %s>'%getattr(self, 'name', '(anonymous)')
    >
    > import operator
    > [p.name for p in sorted(players, key=operator.attrgetter('attacking'), reverse=True)]


    Just happened to read this thread and wanted to say this is a neat
    little example-- thank you! I have a couple of followup questions.

    (1) Is there a performance penalty for using key=operator.attrgetter()?
    (2) The Player class looks like a nice model for a data table when one
    wants to sort by arbitrary column. Would you agree?
    (3) Suppose one wished to construct a player list from a collection of
    attribute lists, e.g.,

    names = ['bob', 'sam', 'linda']
    attack = [7, 5, 8]
    defense = [6, 8, 6]
    # construct players list here

    Can you recommend an efficient way to construct the player list?

    Thanks!
    Marcus
     
    Marcus Goldfish, Apr 3, 2005
    #5
  6. Ben

    James Stroud Guest

    On Saturday 02 April 2005 08:44 pm, Marcus Goldfish wrote:
    > (2) The Player class looks like a nice model for a data table when one
    > wants to sort by arbitrary column. Would you agree?


    The Player class is (and any class) is absolutely fabulous when you have
    heterogenous data (string, int, etc). I would not fall into the trap of LoDs
    (Lists of Dictionaries). They get unwieldy because you always have to manage
    them with functions. You end up writing a module built around your specific
    dictionary and you end up with a duct-taped object oriented design anyway.
    Classes are way better--so use them up front, even if you think that your
    data structure will never be complicated enough to warrant a class. It
    eventually will if it is worth a damn to begin with. Given this is a soccer
    team we are talking about, it is definitely worth being a full fledged class.
    However, if it were basketball...

    > (3) Suppose one wished to construct a player list...[snip]


    team = [Player(azip[0],azip[1],azip[2]) for azip in zip(names,attack,defense)]


    You have to love listcomp.

    Better (IMHO) would be

    team = [Player(azip) for azip in zip(names,attack,defense)]

    where a Player might come to life with

    class Player(object):
    def __init__(self, atup):
    self.name, self.attack, self.defense = atup

    BUT, even way better (again, IMHO) would be

    ateam = Team(zip(names,attack,defense))

    where team could be initialized by a tuple:

    class Team(list):
    def __init__(self, azip):
    for azip in alist:
    self.data.append(Player(atup))

    James

    --
    James Stroud, Ph.D.
    UCLA-DOE Institute for Genomics and Proteomics
    Box 951570
    Los Angeles, CA 90095

    http://www.jamesstroud.com/
     
    James Stroud, Apr 3, 2005
    #6
  7. Ben

    James Stroud Guest

    On Saturday 02 April 2005 09:51 pm, James Stroud wrote:
    > where team could be initialized by a tuple:
    >
    >   class Team(list):
    >     def __init__(self, azip):
    >       for azip in alist:
    >         self.data.append(Player(atup))


    Sorry, this should read:

    where team could be initialized by a list of tuples:

    class Team(list):
    def __init__(self, azip):
    for atup in azip:
    self.data.append(Player(atup))

    --
    James Stroud, Ph.D.
    UCLA-DOE Institute for Genomics and Proteomics
    Box 951570
    Los Angeles, CA 90095

    http://www.jamesstroud.com/
     
    James Stroud, Apr 3, 2005
    #7
  8. On Sat, 2 Apr 2005 23:44:11 -0500, Marcus Goldfish <> wrote:

    >> class Player(object):
    >> def __init__(self, **kw): self.__dict__.update(kw)
    >> def __repr__(self): return '<Player %s>'%getattr(self, 'name', '(anonymous)')
    >>
    >> import operator
    >> [p.name for p in sorted(players, key=operator.attrgetter('attacking'), reverse=True)]

    >
    >Just happened to read this thread and wanted to say this is a neat
    >little example-- thank you! I have a couple of followup questions.
    >
    > (1) Is there a performance penalty for using key=operator.attrgetter()?

    I would think sorted would make it as efficient as possible, but possibly.
    I can conceive of low level optimization for key=<some C builtin that can be recognized>
    But timing is best ;-) Also, vs what? There are a number of alternatives.

    > (2) The Player class looks like a nice model for a data table when one
    > wants to sort by arbitrary column. Would you agree?

    Depends on scale, and what else use you have for a custom object representation. E.g.,
    (using below lists available from interactive session below) a plain dict by names (unique required)
    with (attack, defense) tuples as values is probably pretty efficient and fast.

    >>> dict(zip(names, zip(attack, defense)))

    {'linda': (8, 6), 'bob': (7, 6), 'sam': (5, 8)}

    But if objects are going to be complex and have methods or properties, OO makes it easy.

    > (3) Suppose one wished to construct a player list from a collection of
    > attribute lists, e.g.,
    >
    > names = ['bob', 'sam', 'linda']
    > attack = [7, 5, 8]
    > defense = [6, 8, 6]
    > # construct players list here
    >
    > Can you recommend an efficient way to construct the player list?
    >

    I wouldn't worry about efficiency unless you are dealing with a database of
    all the worlds teams ;-) (And in that case, you probably want to look into
    interfacing with the database your data is already in, to let it do things
    for you natively e.g. via SQL).

    If you know the "columns" as matching attribute lists as above, zip will associate them
    into tuples. Also, I used a keyword argument in the Player __init__ above because I
    wanted to copy and paste the dict calls from the prior post, but knowing exact columns,
    I'd probably do some thing like:

    >>> class Player(object):

    ... def __init__(self, name, attack=None, defense=None): # require name
    ... self.name = name
    ... self.attack = attack
    ... self.defense = defense
    ...
    >>> names = ['bob', 'sam', 'linda']
    >>> attack = [7, 5, 8]
    >>> defense = [6, 8, 6]
    >>>


    Then the players list is just
    >>> players = [Player(*tup) for tup in zip(names, attack, defense)]

    where *tup unpacks a tuple from the output of zip into the arg list of Player's __init__.

    And you can extract the names like
    >>> [player.name for player in players]

    ['bob', 'sam', 'linda']

    Or whatever you want
    >>> for player in players: print player.name, player.attack, player.defense

    ...
    bob 7 6
    sam 5 8
    linda 8 6

    As mentioned, zip makes tuples of corresponding elements of its argument lists:
    >>> zip(names, attack, defense)

    [('bob', 7, 6), ('sam', 5, 8), ('linda', 8, 6)]

    If you had huge input lists, you could avoid the terporary tuple list using
    >>> import itertools
    >>> iplayers = list(itertools.starmap(Player, itertools.izip(names, attack, defense)))
    >>> for player in iplayers: print player.name, player.attack, player.defense

    ...
    bob 7 6
    sam 5 8
    linda 8 6

    You can look into __slots__ if you want to have objects but need reduced memory footprint.
    But don't worry about optimizing 'til you can prove you need it, unless just for fun ;-)

    Ok. That's enough relief for me. Got other stuff ...

    Regards,
    Bengt Richter
     
    Bengt Richter, Apr 3, 2005
    #8
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Max
    Replies:
    1
    Views:
    484
    Joe Kesselman
    Sep 22, 2006
  2. P4trykx
    Replies:
    2
    Views:
    1,826
    bruce barker
    Jan 31, 2007
  3. james_027

    class attributes & data attributes

    james_027, Jun 20, 2007, in forum: Python
    Replies:
    2
    Views:
    377
    Bruno Desthuilliers
    Jun 20, 2007
  4. Kyle Schmitt
    Replies:
    3
    Views:
    194
    Kyle Schmitt
    Jul 24, 2007
  5. Jayden
    Replies:
    16
    Views:
    528
    Steven D'Aprano
    Sep 29, 2012
Loading...

Share This Page