Skip to content
Advertisement

How to use map() on lists with different length, fill shortest lists with custom value [closed]

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.

User contributions licensed under: CC BY-SA
3 People found this is helpful
Advertisement