Find key value in a list of dictionaries - Python
The New Zealand Story - Taito corporation.

Find key value in a list of dictionaries - Python

Let's say you have an application to store all your CDs. To keep this simple, let's say you only store Artist Name and a List of Albums in a Dictionary for each artist in your collection. Your collection is a List.

So at some point you have something like this:

collection = [ {'artist': "Pink Floyd", 'albums': ["Wish You Were Here", "The Wall", "The Division Bell"]}, 
               {'artist': "Pearl Jam", 'albums': ["Ten", "Vitalogy"]},
               {'artist': "Pink", 'albums': ["Missundaztood"]} ]        

Now let's go ahead and write a function to search this collection to retrieve the list of albums from a given Artist.

The most naive approach would be to iterate through the list, and check the 'artist' key for each dictionary. Simple, right? Let's write that:

def getAlbums(collection, artist):
  for d in collection:
    if (d['artist'] == artist):
      return d['albums']         

And run it.

Python 3.7.7 (default, Mar 10 2020, 15:43:33
[Clang 11.0.0 (clang-1100.0.33.17)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> collection = [ {'artist': "Pink Floyd", 'albums': ["Wish You Were Here", "The Wall", "The Division Bell"]},
... {'artist': "Pearl Jam", 'albums': ["Ten", "Vitalogy"]},
... {'artist': "Pink", 'albums': ["Missundaztood"]} ]
>>> def getAlbums(collection, artist):
...   for d in collection:
...     if (d['artist'] == artist):
...       return d['albums']
...
>>> getAlbums(collection, 'Pink')
['Missundaztood']
>>> getAlbums(collection, 'Pearl Jam')
['Ten', 'Vitalogy']
>>>)        

Seems to work. Great!

But as you may know, there are many ways to do the same thing on Python (love it or hate it). So, let's look for another solution, for example we can use a generator expression that allows you to declare a function that behaves like an iterator.

A generator expression is a compact generator notation in parentheses.

Without getting in too much detail (RTFM), let's write a GE and then use the built-in function next() to get the result.

>>> g = (a for a in collection if a.get('artist') == 'Pink'
>>> type(g)
<class 'generator'>
>>> next(g)
{'artist': 'Pink', 'albums': ['Missundaztood']})        

It works like a charm. Let's write this into another function with some minor arrangements:

def getAlbumsGE(collection, artist):
   return next((a['albums'] for a in collection if a.get('artist') == artist), None)        

Two things to note:

  • GE always needs to be directly inside a set of parentheses.
  • next() function will return the value None when exhausted. This means, no item found.

 Let's see if works.

>>> def getAlbumsGE(collection, artist)
...    return next((a['albums'] for a in collection if a.get('artist') == artist), None)
...
>>> getAlbumsGE(collection, 'Pink')
['Missundaztood']:        

Pretty cool, right?

Finally, let's try something else, adding some other nice Python tricks.

The filter() function applies a function to an iterable object and construct an iterator with the items that returns True to that function. To complete this solution we'll need to write a function to filter the results, this is an excellent opportunity to use a Lambda Expression.

Lambda expressions (sometimes called lambda forms) are used to create anonymous functions.

Let's go ahead and write a third function to retrieve the albums list, this time using filter() and lambda to get a new iterator and then the next function to get the result.

def getAlbumsFilter(collection, artist):
  d = next(filter(lambda a : a['artist'] == artist, collection), None)
  return d['albums'] if d is not None else d         

As we want only the albums list and not the whole dictionary, I've added a conditional expression in the return statement.

Conditional expressions (sometimes called a “ternary operator”) have the lowest priority of all Python operations.

And works. :)

>>> def getAlbumsFilter(collection, artist)
...   d = next(filter(lambda a : a['artist'] == artist, collection), None)
...   return d['albums'] if d is not None else d
...
>>> getAlbumsFilter(collection, 'Pink Floyd')
['Wish You Were Here', 'The Wall', 'The Division Bell']:        

But wait! You may be wondering, Is there a way to write this in a single line? And the answer, of course is YES.

So let's introduce another function called map(), that applies a transformation to all the elements of an iterable. Now with the map function and another lambda expression, we have our fourth and final function:

def getAlbumsMap(collection, artist):
  return next(map(lambda l : l['albums'], filter(lambda a : a['artist'] == artist, collection)), None)        

And now the results:

>>> def getAlbumsMap(collection, artist)
...   return next(map(lambda l : l['albums'], filter(lambda a : a['artist'] == artist, collection)), None)
...
>>> getAlbumsMap(collection, 'Pink Floyd')
['Wish You Were Here', 'The Wall', 'The Division Bell']:        

Wow! That was a lot. As I've said before, there are so many ways to do the same thing in Python. This has some ups and downs, but that's for another post.

Today we saw how to use this nice features with iterables:

And, that's all folks! Now go and try this at home. See you next time.

To view or add a comment, sign in

More articles by Javier Valenzani

Others also viewed

Explore content categories