Lambda functions with multiple conditions - python-3.x

Consider the following code snippet.
## Heading ##
def pos(l):
count_positive=0
for i in l:
if i>0:
count_positive+=1
return count_positive
def even(l):
count_even=0
for i in l:
if i%2==0:
count_even+=1
return count_even
list_int=[[2,-3,-6,10],[10,34,26,87],[1,-2,-3,4]]
list_int=sorted(list_int,key=lambda x: (pos(x),even(x)))
print(list_int)
Lambda functions can't have more than one expression.
But in the code above, I am trying to sort the 2D list first based on number of positive elements and then based on number of even elements. Doesn't this mean that there are two expressions in the lambda function? Or is it like, as I have enclosed the two conditions inside a tuple, it would be considered as one single condition?

Doesn't this mean that there are two expressions in the lambda function?
Yes, there's two expressions, but there's only one expression being returned. When you do
lambda x: (pos(x), even(x))
you're creating a lambda that returns a single value: a tuple with two elements. You can see this by doing
f = lambda x: (pos(x), even(x))
print(f([1, 2, 3, 4])) # Outputs (4, 2)
print(f([-1, -2, -3, -4])) # Outputs (0, 2)
Since it returns a tuple, when you use this as your sorted key, it compares using tuple comparison.
About lambdas, Python documentation says
[Lambdas] are syntactically restricted to a single expression.
It means that you can't do
f = lambda x: pos(x), even(x)
# It'll be parsed as f = ((lambda x: pos(x)), (even(x)))
f = lambda x: return pos(x); return even(x)
# It'll throw a SyntaxError
Or is it like, as I have enclosed the two conditions inside a tuple, it would be considered as one single condition?
No, because this doesn't make sense. A single condition would only be considered if you connect them explicitely with a operator, such as addition:
f = lambda x: pos(x) + even(x)
# Sorts the lists based on the sum of the count of the positive
# numbers with the count of the even numbers

You have one expression - a tuple that calls two functions to get its values. A single "expression" can call multiple functions.
What "Lambda functions can't have more than one expression" means if that you can't have multiple "lines of code" within a lambda, meaning you can't do something like:
lambda x: print(x) return x+1

Related

Passing an arbitrary number of parameters to a function in python

I have a python function which takes as input an arbitrary number of parameters. I beleive this is implemented via *args (thanks #Anurag Wagh for pointing this out). I would like to be able to pass to it a list of values. Here is the specific code I have:
from sympy import solve_poly_system, symbols
x,y,z = symbols('x y z')
print(solve_poly_system([y**2 - x**3 + 1, y*x], x, y))
Instead of passing x and y to solve_poly_system, I want to be able to pass it a list L something like so:
print(solve_poly_system([y**2 - x**3 + 1, y*x], L))
where L = [x,y].
Is this possible? Please note, although I am interested in the specific case of the solve_poly_system function, I am more broadly interested in the passing a list to any function in python that takes an arbitrary number of inputs.
To put this another way, I want to know how to pass a list of values to a function which takes *args as input. In particular I am interested in the case where the length of the list is not known until run time and may change during run time.
From your question, it looks like you know how to use *args in function definition and you are looking for a way to pass all the elements of a list to that function regardless of the length of the list. If that's your question, then here's your answer:
def function(x, *args):
print(x)
print(args)
x = 10
l = [5, 6, 7, 8]
function(x, *l)
Output:
10
(5, 6, 7, 8)

comparing elements of a list from an *args

I have this function that I need to compare the strings in a list to a *args
The reason being is that, the user should be able to type any words in the 2nd argument. However when I try to compare the strings to the *args it doesn't give me any results
def title_case2(title, *minor_words):
for x in title.split():
if x in minor_words:
print(x)
Assuming I ran the function with the parameters below. I was hoping it would display a and of since these words are found on those 2 entries.
title_case2('a clash of KINGS','a an the of')
*args is a tuple of arguments, so you're actually checking if x is in ('a an the of',). So either pass your argument as:
title_case2('a clash of KINGS', *'a an the of'.split())
Or, use this as your test:
if any(x in y for y in minor_words):
In either of the above cases the output is:
a
of
This is one approach.
Ex:
def title_case2(title, *minor_words):
minor_words = [j for i in minor_words for j in i.split()] #Create a flat list.
for x in title.split():
if x in minor_words:
print(x)
title_case2('a clash of KINGS','a an the of', "Jam")
using a for-loop instead of list comprehension
def title_case2(title, *minor_words):
minor_words_r = []
for i in minor_words:
for j in i.split():
minor_words_r.append(j)
for x in title.split():
if x in minor_words_r:
print(x)

Python 3.X: Implement returnGreater() function using a list of integers and a value

The function must return a list consisting of the numbers greater than the second number in the function
It must be able to do the following when functioning:
returnGreater([1,2,3,4,5], 3)
[4,5]
returnGreater([-8,2,-4,1,3,-5],3)
[]
Here's what I have (I've gone through a few iterations), though I get a Type Error for trying to use a ">" symbol between an int and list:
def returnGreater (x,y):
"x:list(int) , return:list(int)"
#greater: int
greater = []
for y in x:
#x: int
if x > y:
x = greater
return greater
You're using the name y for two different things in your code. It's both an argument (the number to compare against) and the loop variable. You should use a different name for one of those.
I'd strongly suggest picking meaningful names, as that will make it much clearer what each variable means, as well as making it much less likely you'll use the same name for two different things. For instance, here's how I'd name the variables (getting rid of both x and y):
def returnGreater(list_of_numbers, threshold):
greater = []
for item in list_of_numbers:
if item > threshold:
greater.append(item)
return greater
You had another issue with the line x = greater, which didn't do anything useful (it replaced the reference to the original list with a reference to the empty greater list. You should be appending the item you just compared to the greater list instead.
I recommend filter. Easy and Graceful way.
def returnGreater(x, y):
return list(filter(lambda a:a>y, x))
It means, filter each element a in list x using lambda whether a is greater than y or not.
List Comprehensions
def returnGreater(_list, value):
return [x for x in _list if x > value]

Getting a list item with the max evaluation in a list of tuples in Python

Given this list of tuples:
my_tuples = [(1,2), (3,4)]
and the following evaluation function:
def evaluate(item_tuple):
return item_tuple[0] * 2
Question: how can I get the list item (tuple) that has the highest evaluation value? (I'm guessing I can use a list comprehension for this)
def max_item(tuples_list, evaluation_fn):
'''Should return the tuple that scores max using evaluation_fn'''
# TODO Implement
# This should pass
assertEqual((3,4), max_item(my_tuples, evaluate))
Correct me if I'm wrong, you want the list of tuples sorted by the result of multiplying one of the values inside the tuple with x (in your example above it would be the first value of the tuple multiplied by 2).
If so, you can do it this way:
from operator import itemgetter
sorted(l, key=itemgetter(0 * 2), reverse=True)
I managed to do it this way:
def max_item(tuples_list, evaluation_fn):
zipped = zip(map(evaluation_fn, tuples_list), tuples_list)
return max(zipped, key=lambda i:i[0])[1]
I don't know if there's a simpler (more pythonic?) way to solve it though.
Edit
I figured how I could use a list comprehension to make it more succinct/readable:
def max_item(tuples_list, evaluation_fn):
return max([(evaluation_fn(i), i) for i in tuples_list])[1]

Can you call 2 args from a function into another function? [duplicate]

So, Python functions can return multiple values. It struck me that it would be convenient (though a bit less readable) if the following were possible.
a = [[1,2],[3,4]]
def cord():
return 1, 1
def printa(y,x):
print a[y][x]
printa(cord())
...but it's not. I'm aware that you can do the same thing by dumping both return values into temporary variables, but it doesn't seem as elegant. I could also rewrite the last line as "printa(cord()[0], cord()[1])", but that would execute cord() twice.
Is there an elegant, efficient way to do this? Or should I just see that quote about premature optimization and forget about this?
printa(*cord())
The * here is an argument expansion operator... well I forget what it's technically called, but in this context it takes a list or tuple and expands it out so the function sees each list/tuple element as a separate argument.
It's basically the reverse of the * you might use to capture all non-keyword arguments in a function definition:
def fn(*args):
# args is now a tuple of the non-keyworded arguments
print args
fn(1, 2, 3, 4, 5)
prints (1, 2, 3, 4, 5)
fn(*[1, 2, 3, 4, 5])
does the same.
Try this:
>>> def cord():
... return (1, 1)
...
>>> def printa(y, x):
... print a[y][x]
...
>>> a=[[1,2],[3,4]]
>>> printa(*cord())
4
The star basically says "use the elements of this collection as positional arguments." You can do the same with a dict for keyword arguments using two stars:
>>> a = {'a' : 2, 'b' : 3}
>>> def foo(a, b):
... print a, b
...
>>> foo(**a)
2 3
Actually, Python doesn't really return multiple values, it returns one value which can be multiple values packed into a tuple. Which means that you need to "unpack" the returned value in order to have multiples.
A statement like
x,y = cord()
does that, but directly using the return value as you did in
printa(cord())
doesn't, that's why you need to use the asterisk. Perhaps a nice term for it might be "implicit tuple unpacking" or "tuple unpacking without assignment".

Resources