Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pythonic way to fetch all elements in a dictionary, falling between two keys?

Tags:

python

I have a dictionary object, and I want to extract a subset of the dictionary (i.e. return another dictionary), which contains all elements of the parent dictionary where the key matches a certain criteria.

For example:

parent_dict = {1: 'Homer',
               2: 'Bart',
               3: 'Lisa',
               4: 'Marge',
               5: 'Maggie'
               }


def filter_func(somedict, key_criteria_func):
    pass

I want to write (in a pythonic way), filter_func, so that I can call it like this:

filter_func(parent_dict, ">2 and <4")

which will return the new dict:

{ 3: 'Lisa' }

What is the most pythonic way to write filter_func?

To keep things simple, I will limit the criteria to simple boolean operations.

[[Edit]]

This is the output when I try the following command:

>>> {key:val for key,val in parent_dict.iteritems() if 2 < key < 4 }
  File "<stdin>", line 1
    {key:val for key,val in parent_dict.iteritems() if 2 < key < 4 }
               ^
SyntaxError: invalid syntax

BTW, I'm running Python 2.6.5

like image 619
Homunculus Reticulli Avatar asked Feb 23 '23 00:02

Homunculus Reticulli


1 Answers

Solution

Starting from python 2.7, you can use dictionary comprehension. There are like list comprehensions, but applied to a dictionary:

>>> parent_dict = {1: 'Homer',
...                2: 'Bart',
...                3: 'Lisa',
...                4: 'Marge',
...                5: 'Maggie'
...                }
>>> {key:val for key,val in parent_dict.iteritems() if 2 < key < 4 }
1: {3: 'Lisa'}

You probably don't need to make it a function, but if you do, you can just use a lambda function as a filter:

>>> def filter_func(somedict, key_criteria_func):
...     return {k:v for k, v in somedict.iteritems() if  key_criteria_func(k)}
... 
... filter_func(parent_dict, lambda x: 2 < x < 4)
2: {3: 'Lisa'}

For Python 2.6.5 and all version before 2.7, replace the dict comprehension with:

dict((k,v) for k,v in parent_dict.iteritems() if 2 < k < 4)

Why a lambda function ?

Lambda function are not magic, it's just a way to easily create fonction on the fly. You can do everything you do with lambda witout it, the only difference is that lambdas are expression, and therefor can be used directly between parenthis.

Compare:

>>> func = lambda x: 2 < x < 4
>>> func(3)
True

With:

>>> def func(x):
...    return 2 < x < 4
...
>>> func(3)
True

It's exactly the same and produce the same function, except the lambda function won't have a name. But you don't care, on your case you don't need a name, you just need a reference to call it, and the variable func contains this reference.

The lambda syntax is weird because:

  • You don't need parenthesis for the parameters (you don't even need parameter)
  • you don't do def var(param): but var = lambda param:. Nothing magic, it's just syntax
  • you can't make a 2 lines lambda: the return result must fit in one instruction.
  • you don't use the return keyword: the right part of the lambda is returned automatically

Now the nice thing with a lamda, is that since it's an expression, you can use it between parenthese, meaning you can create and pass your fonction à the same time.

Compare:

>>> filter_func(parent_dict, lambda x: 2 < x < 4)

With:

>>> def func(x):
...    return 2 < x < 4
...
>>> filter_func(parent_dict, func)

It's exactly the same. The lambda is just shorter.

The hard part here is to understand that you can pass a function as a parameter in Python because everything in Python is an object, including functions.

You can even do this:

>>> def func():
...    print "test"
...
>>> ref_to_func = func # assign the function refence to another var
>>> del func # delete this label
>>> ref_to_func() # call the function from this label
test

And you can even define a fonction on one line:

>>> def func(): print "test"
>>> func() 
test

But you can't do this:

filter_func(parent_dict, def func(x): 2 < x 4 )

Which is where lambdas are useful.

like image 192
e-satis Avatar answered Apr 06 '23 22:04

e-satis