I want to apply a function on multiple lists using map, and fill the shortest list(s) with a custom value. I have created a solution using a for loop and zip_longest but I think it could be improved using map()
. I’m unaware which of the list(s) is the longest, they could have equal lengths. Here’s my implementation:
import itertools
items1 = [1, 2, 3, 4]
items2 = [1, 2]
items3 = [1, 1, 1]
def multiply(a, b, c):
if a is None:
a = 0.5 # custom value, could also be set elsewhere
if b is None:
b = 0.4
if c is None:
c = 0.3
return a * b * c
squared_numbers = []
for numbers in itertools.zip_longest(items1, items2, items3):
squared_numbers.append(multiply(*numbers))
Value of squared_numbers
:
[1, 4, 1.2000000000000002, 0.48]
Bonus: I prefer to set the custom values via def multiply(a=5, b=0.4, c=0.3)
, but I’m not sure if this is possible.
EDIT: The code works fine, I’m just curious if it can be optimized further.
Advertisement
Answer
Maybe you meant itertools.starmap
instead of map
? Here’s something I came up with but I wouldn’t really say it’s better than what you’ve already written:
from itertools import zip_longest, starmap
lists = [
[1, 2, 3, 4],
[1, 2],
[1, 1, 1]
]
def multiply(*args):
from functools import reduce
from operator import mul
defaults = [0.5, 0.4, 0.3]
return reduce(mul, (arg or default for arg, default in zip(args, defaults)))
squared_numbers = list(starmap(multiply, zip_longest(*lists)))
print(squared_numbers)
Output:
[1, 4, 1.2000000000000002, 0.48]
>>>
If you’re using itertools.zip_longest
, you can’t really get around using a fillvalue
– in our case that means we will always pass three arguments to multiply
, even if all- or some of them are None
(itertools.zip_longest
‘s default fillvalue
). This means you can’t use default positional-arguments, because they only take effect when not enough positional-arguments are passed in, which will never be the case.
The generator expression in functools.reduce
works through short-circuit evaluation. The expression arg or default
will evaluate to arg
if arg
is truthy, and default
otherwise. None
is considered falsey, so if arg
is None
, the expression evaluates to default
.