itemgetter
:
This one is used when you want to select elements by their indices:
from operator import itemgetter
numbers = [[0, 1, 2, 3],
[4, 5, 6, 7],
[8, 9, 0, 1]]
result_1 = map(lambda x: x[0], numbers)
result_2 = (x[0] for x in numbers)
result_3 = map(itemgetter(0), numbers)
# [0, 4, 8]
While it is longer than generator expression in the given example, it will actually be shorter when you want to select several elements at once:
result_1 = map(lambda x: (x[0], x[2], x[3]), numbers)
result_2 = ((x[0], x[2], x[3]) for x in numbers)
result_3 = map(itemgetter(0, 2, 3), numbers)
# [(0, 2, 3), (4, 6, 7), (8, 0, 1)]
You can also use itemgetter
with dictionaries:
data = [{'time': 0, 'temperature': 290, 'pressure': 1.01},
{'time': 10, 'temperature': 295, 'pressure': 1.04},
{'time': 20, 'temperature': 300, 'pressure': 1.07}]
result_1 = map(lambda x: (x['time'], x['pressure']), data)
result_2 = ((x['time'], x['pressure']) for x in data)
result_3 = map(itemgetter('time', 'pressure'), data)
# [(0, 1.01), (10, 1.04), (20, 1.07)]
attrgetter
This one is used to get attributes of objects:
from collections import namedtuple
from operator import attrgetter
Person = namedtuple('Person', ['name', 'surname', 'age', 'car'])
people = [Person(name='John', surname='Smith', age=40, car='Tesla'),
Person(name='Mike', surname='Smith', age=50, car=None)]
result_1 = map(lambda x: (x.name, x.age, x.car), people)
result_2 = ((x.name, x.age, x.car) for x in people)
result_3 = map(attrgetter('name', 'age', 'car'), people)
# [('John', 40, 'Tesla'), ('Mike', 50, None)]
It is longer than the generator expression version, so I'm leaving it here just for completeness. Of course, you can import attrgetter
as get
and it will be shorter but nobody really does that. Using attrgetter
has an advantage, though, that you could take it out as a separate callable that could be used more than once (same as lambda
):
get_features = attrgetter('name', 'age', 'car')
group_1_features = map(get_features, people)
group_2_features = map(get_features, other_people)
...
Another alternative worth to mention is using fget
method of properties:
result = map(Person.age.fget, people)
I've never seen anyone using it though, so prepare to give explanation to people who will read your code if you use it.
contains
:
Used to check if an element is present in another object/container:
from functools import partial
from operator import contains
fruits = {'apple', 'peach', 'orange'}
objects = ['apple', 'table', 'orange']
result_1 = map(lambda x: x in fruits, objects)
result_2 = (x in fruits for x in objects)
is_fruit = partial(contains, fruits)
result_3 = map(is_fruit, objects)
# [True, False, True]
This, though, has a drawback of creating an additional partial
object. Another way to write this would be to use __contains__
method:
result = map(fruits.__contains__, objects)
But some people argue that it is a bad practice to use dunder methods as those are just for a private use.
Mathematical operations:
For example, if you would want to sum pairs of numbers, you could use operator.add
:
from itertools import starmap
from operator import add
pairs = [(1, 2), (4, 3), (1, 10), (2, 5)]
result_1 = map(lambda x: x[0] + x[1], pairs)
result_2 = (x + y for x, y in pairs)
result_3 = starmap(add, pairs)
# [3, 7, 11, 7]
If you are fine with two additional imports then this is the shortest option. Note that we use itertools.starmap
here because we need to unpack tuples of numbers before supplying them to add(a, b)
function.