Take the 2-minute tour ×

I have a list of people:

    {'name' : 'John', 'wins' : 10 },
    {'name' : 'Sally', 'wins' : 0 },
    {'name' : 'Fred', 'wins' : 3 },
    {'name' : 'Mary', 'wins' : 6 }

I am adding wins using a list of names (['Fred', 'Mary', 'Sally']). I don't know if the name is in the list of people already, and I need to insert a new record if not. Currently I'm doing the following:

name = 'John'
person = None
pidx = None
for p in people_list:
    if p['name'] == name:
        person = p
        pidx = people_list.index(p)
if person is None:
    person = {'name' : name, 'wins' : 0}
person['wins'] += 1
if pidx is None:
    people_list[pidx] = person

Is there a better way to do this with a list? Given that I'm saving this to MongoDB I can't use a dict as it will save as an object and I want to use native array functions for sorting and mapping that aren't available for objects.

share|improve this question

5 Answers 5

up vote 5 down vote accepted

I'm assuming here that you don't want to use any structure other than the list. Your code should work, although you unnecessarily write the dictionary back to the list after updating it. Dictionaries are copied by reference, so once you update it, it stays updated in the list. After a little housekeeping, your code could look like this:

def add_win(people_list, name):
    person = find_person(people_list, name)
    person['wins'] += 1

def find_person(people_list, name):
    for person in people_list:
        if person['name'] == name:
            return person
    return person
share|improve this answer

Yes, use a dict.

wins = {}
for name in winners:
    wins.setdefault(name, 0)
    wins[name] += 1


index = {}
for name in wins:
    person = index.setdefault(name, { 'name' : name, 'wins': 0 })
    if person['wins'] == 0:
    person['wins'] += 1
share|improve this answer
I don't want to use a dict. I want to use a list. Saying "use a dict" is useless because I want it to be a list. I'm saving this to MongoDB, using a dict makes it an object and I want to use some native array functions. –  Josh K Feb 25 '11 at 17:22
@Josh K: see my answer about using a list and a set –  Nick Bastin Feb 25 '11 at 17:24
@MAK: What's not clear? I know that using a dict would provide a cleaner access pattern but I can't. –  Josh K Feb 25 '11 at 17:28
@Josh: the answer is still "use a dict". See my edit for how you can do both. –  tangentstorm Feb 25 '11 at 17:33

Your access pattern dictates the use of a different data structure (or at least another helper data structure). Scanning the list as you're doing is in fact the right thing to do if you're using a list, but you shouldn't be using a list (if you want it to be efficient, anyhow).

If the order of the list doesn't matter, you should use a Dictionary (python dict). If it does, you should use an OrderedDict from the collections module.

You could also use two separate data structures - the list you already have, and additionally a set containing just the names in the list so you have quick access to test inclusion or not. However, the set doesn't help you access the actual name data quickly (you'd still have to do a linear search in the list for that), so it would only be a helpful pattern if you merely were testing inclusion, but otherwise always walking the list as it was inserted.

Edit: it seems like what you might actually want is a list and a dict, where the dictionary is a mapping between the name and the index in the list. Alternatively you could still use a dict or OrderedDict, but insert them into Mongo as an array by using dict.iteritems() to create an array (or what would look like an array to Mongo) on insertion. You could use various mutators from zip to things in itertools to dynamically build up the objects you need in your resultant array.

share|improve this answer
Note that collections.OrderedDict is new in Python 2.7, but there's an equivalent recipe for OrderedDict for earlier versions. See the documentation for details. –  eksortso Feb 25 '11 at 17:36

If you don't want a dict permanently use one temporarily.

people = [

wins = ['Fred', 'Mary', 'Sally']

people_dict = dict((p["name"], p) for p in people)

for winner in wins:
    people_dict[winner].setdefault("wins", 0)
    people_dict[winner]["wins"] += 1

people = people_dict.values()
share|improve this answer
Can you convert from a list to a dict? I'm pulling a list out of MongoDB. –  Josh K Feb 25 '11 at 17:37
that is precisely what is happening in the example code on the line where people_dict is defined. The key is the name, the value is the dict you have. –  StephenPaulger Feb 25 '11 at 17:39
What's the processing overhead for converting to and from the list / dict? –  Josh K Feb 25 '11 at 17:44
Less than the processing overhead of searching a list every time you want to increment a number within it. –  StephenPaulger Feb 26 '11 at 0:45

This specific case is implemented by the collections.Counter type. Along with array generators, this is one expression:

[{'name':name, 'wins':wins}
 for name, wins in Counter(names).items()]

If you want a specific order, sorted() is the easiest way (this also uses a plain generator (), rather than an array generator [], since it's temporary):

sorted(({'name':name, 'wins':wins} for name, wins in Counter(names).items()),
       key=lambda item: item['name'])

Where item['name'] could be item['wins'] or any other comparable expression.

share|improve this answer

Your Answer


