Can I insert a tuple (or a list) of arguments into a function using map?

Viewed 182

My goal is to create a function that would check whether a number is in a given range.

So, I've created a function range_check() that takes three arguments - number, low and high. I've also created 4 test cases that are stored as tuples. The first three test cases are true, the last one is false.

def range_check(num, low, high):
    return low <= num <= high


test_values = [(2, 1, 4), (5, 2, 7), (3, 1, 10), (3, 4, 5)]

for test_case in test_values:
    print(range_check(test_case[0], test_case[1], test_case[2]))

Since I've lately discovered what lambda is and how to use it (I'm still new to Python and programming in general), I wanted to try to solve this using lambda and map (or filter could also be used here, I guess)

test_values = [(2, 1, 4), (5, 2, 7), (3, 1, 10), (3, 4, 5)]
print(list(map(lambda num, low, high: low <= num <= high, test_values)))

However, this gives an error - lambda is missing 2 required arguments - low and high.

Is there any way how I can insert a tuple of arguments into a function or lambda like this?

The only thing that I came up with is to make lists of numbers, lows and highs.

nums = [2, 5, 3, 3]
lows = [1, 2, 1, 4]
highs = [4, 7, 10, 5]

print(list(map(lambda num, low, high: low <= num <= high, nums, lows, highs)))

But this doesn't seem to be much easier and may be hard to understand later, in my opinion.

Thanks a lot in advance for any help or ideas.

4 Answers

the lambda function can't unpack the arguments automatically. map passes the tuple to the function, not 3 arguments. You have to take one argument as a tuple and access the elements:

test_values = [(2, 1, 4), (5, 2, 7), (3, 1, 10), (3, 4, 5)]
print(list(map(lambda t: t[1] <= t[0] <= t[2], test_values)))

that's why a simple list comprehension is much better: you can unpack the tuple in the loop:

[low <= num <= high for num,low,high in test_values]

it's also faster as you don't have to chain function calls, and less cryptic. map + lambda combination isn't the best in speed and readability.

result is [True, True, True, False] for both.

You are seeing the difference between taking a tuple as an argument, and taking the elements of a tuple as separate arguments. You could write

print(list(map(lambda t: t[1] <= t[0] <= t[2], test_values)))

or you can use itertools.starmap, which effectively unpacks the tuple for you.

from itertools import startup

print(list(starmap(lambda num, low, high: low <= num <= high, test_values)))

In Python, though, it is usually clearer to use a list comprehension to build a list than explicit use of map and a function:

print([low <= num <= high for num, low, high in test_values])

You can use zip and tuple unpacking:

    test_values = [(2, 1, 4), (5, 2, 7), (3, 1, 10), (3, 4, 5)]

    print(list(map(lambda num, low, high: low <= num <= high, *zip(*test_values))))

Returns [True, True, True, False]

I would add that a list comprehension is vastly more readable for this kind of thing. Even Guido hates map...

I would do this just with 1-line for loop like this:

print([range_check(*x) for x in test_values])

This * in front of x in function argument makes your tuple to unpack into more variables.

Related