I am trying to use lambda function to add up all the numbers. I am getting following error,
Syntax error - "Generator expression must be parenthesized if not sole
argument"
def solve(s):
return reduce(lambda x, y: x + int(y) for y in s if y.isdigit(),s)
print solve('1o2i212')
It works if I use the following.
def solve(s):
return reduce(lambda x, y: x + y, [int(i) for i in s if i.isdigit()])
print solve('1o2i212')
Python 3 users should do a from functools import reduce. reduce has been moved out of builtin functions from Python 3.
return reduce(lambda x, y: x + int(y),(y for y in s if y.isdigit()),0)
output
8
Explanation
lambda x, y: x + int(y), #x is the aggregating sum
(y for y in s if y.isdigit()), #reduced over all the digits in s
0 #x=0 the starting sum value.
To understand reduce, check here it needs a starting seed of 0 to avoid conversion errors
If you do not give a starting value:-
>>> def solve(s):
... return reduce(lambda x, y: x + int(y),(y for y in s if y.isdigit()))
...
>>> print(solve('1o2i212'))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in solve
File "<stdin>", line 2, in <lambda>
TypeError: must be str, not int
If you do not want to give a starting value for the aggregation do the below:-
return reduce(lambda x, y: x + y,(int(y) for y in s if y.isdigit()))
Simple solution using List Comprehensions.
def solve(s):
return sum([int(c) for c in s if c.isdigit()])
print(solve('1o2i212'))
Solution using functools.reduce (Python 3):
import functools
def solve(s):
return functools.reduce(lambda x, y: x + int(y),[y for y in s if y.isdigit()],0)
print(solve('1o2i212'))
N.B.: 0 is the initializer which is an optional parameter of functools.reduce.
If the optional initializer is present, it is placed before the items
of the sequence in the calculation, and serves as a default when the
sequence is empty.
Output:
8
Note: Python 3 developers need to use:
from functools import reduce
The signature is reduce(function, iterable[, initializer])
So, you can decompose as follow:
def solve(s):
function = lambda x, y: x + int(y)
iterable = (c for c in s if c.isdigit())
initializer = 0
return reduce(function, iterable, initializer)
print(solve('1o2i212'))
You get 8.
Here, iterable is a generator object.
And notice that initializer is required because the default value is None.
Of cours you can put all things together with parenthesis.
def solve(s):
return reduce(lambda x, y: x + int(y), (c for c in s if c.isdigit()), 0)
You have to understand some things before working with lambda :
How lambda syntax works ;
lambda x,y:x+y #this is lambda function
Now we will pass the argument to this lambda , there are two ways to passing argument first one :
arg=lambda x,y:x+y
print(arg(1,2))
Second method :
print((lambda x,y:x+y)(1,2))
Now if we use reduce with lambda then the syntax is :
print(reduce(lambda x,y:x+y,[1,2,3,4,5]))
So if you are passing a generator expression what should be your lambda syntax:
print(reduce(lambda x,y:x+y,(generator expression)))
and what is your generator expression is:
(y for y in s if y.isdigit())
let's put in lambda syntax:
print(reduce(lambda x,y:x+y,(y for y in s if y.isdigit())))
ok now we don't need print because we are using function and returning the result so:
def solve(s):
return reduce(lambda x,y:x+y,(y for y in s if y.isdigit()))
print(solve('1o2i212'))
when you will run this program you will get :
12212
Because we are adding strings and when you do str(1) + str(2) it is 12 in python not 3 so what we have to correct is convert the str to int there :
def solve(s):
return reduce(lambda x, y: x+y, (int(y) for y in s if y.isdigit()))
print solve('1o2i212')
Now the output is :
8
So which mistake you were doing :
Your generator expression is wrong because you are mixing with generator expression output with lambda parameters :
(int(y) for y in s if y.isdigit()) #this is correct
so change this :
reduce(lambda x, y: x + int(y) for y in s if y.isdigit(),s)
to this :
reduce(lambda x, y: x+y, (int(y) for y in s if y.isdigit()))
I think something like this should actually be enough for the problem.
solve = lambda x: sum([int(i) for i in x if i.isdigit()])
solve('1o2i212') #8
Related
When I assign anonymous function to the variable using ternary operator with the true condition, I can call the variable as a normal function.
>>> a = lambda x, y: x + y if True else lambda x, y: x * y
>>> a(1, 2)
3
But when the condition is false and the function to be assigned is after the word else, I get something like this. I have no idea what mechanisms stand behind such a weird behaviour. Is there any syntax nuances? Or any possibility to use ternary operator in cases like this one?
>>> a = lambda x, y: x + y if False else lambda x, y: x * y
>>> a(1, 2)
<function <lambda>.<locals>.<lambda> at 0x10916aee0>
You need to use parentheses to indicate your meaning.
You mean
(lambda x, y: x + y) if True
else (lambda x, y: x * y)
but you have
lambda x, y:
(x + y if True
else lambda x, y: x * y)
The ... if ... else ... operator has higher precedence than lambda. See https://docs.python.org/3/reference/expressions.html#operator-precedence.
This question already has answers here:
if/else in a list comprehension
(12 answers)
Closed 3 years ago.
I have a reduce function that looks like this:
reduce(lambda x, y: x + y, [foo(x) for x in listValue], [])
I also have another function called goo and I want to use it when x achieves some condition, for example x >= 10 inside the reduce .
My idea is something like:
reduce(lambda x, y: x + y, [foo(x) for x in listValue if x < 10 else goo(x)], [])
but that gives me an error:
File "<stdin>", line 1
reduce(lambda x, y: x + y, [foo(x) for x in listValue if x < 10 else goo(x)], [])
^
SyntaxError: invalid syntax
How to solve this?
for and if are in the wrong order. You first need to specify the if, then the for.
Use this reduce in your code:
reduce(lambda x, y: x + y, [(foo(x) if x < 10 else goo(x)) for x in listValue], [])
When I try to print and see what each function does, I'm able to call only the h function. All others return functions.
Also, can anybody tell me why this code prints 13 and what is happening?
two_to_one = lambda g: (lambda y: g(y,y))`
one_to_two = lambda f: (lambda x, y: f(x) + f(y))
h = one_to_two(two_to_one(lambda x, y: x*y))
print(h(3,2))
That was quite a mind bender!
So let's just break the logic bit by bit. We'll start from h, it is essentially
h = lambda x, y : x*x + y*y
h(3,2) # output is 13
Now, we'll be good programmers and look for repetition. x*x and y*y are essentially the same thing. Why not have a lambda that does that?
a = lambda x: x*x
h = lambda x,y: a(x) + a(y)
h(3,2)
Good, but I want the caller to decide whether to do x*x or x**x or x+x. Everytime I do that I dont want to change a. So I instead pass a lambda to a with whatever operation I want to perform
# a is just a delegator now. It just calls the lambda that it is "initialized" with passing the values twice
a = lambda lambdaIAmPassing: (lambda someValue: lambdaIAmPassing(someValue, someValue))
# lets pass a multiplication lambda
mul_a = a(lambda x,y: x*y)
# lets pass a addition doing lambda
add_a = a(lambda x,y: x+y)
h = mul_a(3) + mul_a(2)
print h #output is 13
h = add_a(3) + add_a(2)
print h # output is 10
Is this clear? You would have realized now that a is in fact the lambda two_to_one in your question
Now the final step.Do you see any other repetition in the code? we are calling mul_a twice and add_a twice. So to avoid this we define a lambda that calls whatever function is passed to it twice - once per parameter - and adds up the values
# Lambda that adds up the result of the function call
lambda_adder = lambda f: (lambda value1, value2: f(value1) + f(value2))
"Initialize" this lambda with mul_a
h = lambda_adder(mul_a)
h(3,2) # output is 13
Hence we end up with the code in your question
two_to_one = lambda g: (lambda y: g(y,y))
This equals a function which calls a function g, passing it two variables, both y. In this case, g is
lambda x, y: x*y
because that is the argument passed to two_to_one on the third line (h's assignment).
one_to_two = lambda f: (lambda x, y: f(x) + f(y))
This equals a function which returns the sum of two calls to the function f, passing the values x and y. In this case, f is the two_to_one function.
Breaking it down:
first = lambda x, y: x*y
second = lambda y: first(y,y)
third = lambda x, y: second(x) + second(y)
simplifies to:
second = lambda y: y * y
third = lambda x, y: second(x) + second(y)
simplifies to:
third = lambda x, y: x * x + y * y
So, what the code is doing is returning the sum of the squares of the arguments. In this case, they are 3 and 2.
I hope it will be relatively easy to follow.
two_to_one = lambda g: (lambda y: g(y,y))
two_to_one is a function, with an input of a function (g: a function with an input of two parameters (as seen in g(y,y)), and output of a function (with 1 input y, and output of g(y,y)). Meaning it is a function of functions. So when giving two_to_one a two parameter function g, you get back a function, that takes 1 number and outputs g(y,y).
e.g:
two_to_one(lambda x,y:x+y)(3)
6
We gave two_to_one a function that gets two numbers and output their sum, lambda x,y:x+y, and we got back a function that takes 1 number and output its sum with itself two_to_one(lambda x,y:x+y). So with an input of 3 it outputs 6.
Second line is similiar:
one_to_two = lambda f: (lambda x, y: f(x) + f(y))
Take a function f (of 1 parameter - due to f(x)), and give back a function, that gets two parameters (numbers probably) x,y and outputs f(x) + f(y).
Now, for the 13 output - working from inner to outer:
h = one_to_two(two_to_one(lambda x, y: x*y))
lambda x, y: x*y two parameter input - output of multiplication. This is the input of two_to_one so (remember what was written earlier) two_to_one(lambda x, y: x*y) is a function that gets 1 number, and returns it squared. And finally, feeding this function to one_to_two gives a function that gets two numbers (those x,y frim before) and returns their sum of squares.
In total h(3,2) gives 3**2+2**2=13.
I'm writing a python script that should take a list of functions, written as lambda expressions, and return the compose of all the function, but, I have an arrow in the script, maybe because of the way I'm using lambda expression. It seems like even after I give the returned function a number value, I get back a function, and not a number. This is what I've wrote:
def compose1(lst):
if lst == []:
return lambda x: x
else:
temp = (lst[len(lst)-1])
for i in range(len(lst)-2,-1,-1):
temp = lambda x: lst[i](temp)
return lambda x: temp
this is a tast for the function I've wrote, which says I have a mistake.
f = compose1([lambda x: x+1, lambda x: x*2, lambda x: x-1])
for x in range(10):
assert (f(x) == 1 + (x - 1) * 2)
f = compose1([lambda x: x-1, lambda x: x*2, lambda x: x+1])
for x in range(10):
assert (f(x) == (x + 1) * 2) - 1
I would apreciate some halp on this problem..
thanks :)
def compose(*funcs):
"""
compose(func[,...[, func]]) -> function
Return the composition of functions.
For example, compose(foo, bar)(5) == foo(bar(5))
"""
if not all(callable(func) for func in funcs):
raise TypeError('argument must be callable')
funcs = funcs[::-1]
def composition(*args, **kwargs):
args = funcs[0](*args, **kwargs)
for func in funcs[1:]:
args = func(args)
return args
return composition
f = compose(*[lambda x: x+1, lambda x: x*2, lambda x: x-1])
for x in range(10):
assert f(x) == (1 + (x - 1) * 2)
f = compose(*[lambda x: x-1, lambda x: x*2, lambda x: x+1])
for x in range(10):
assert f(x) == ((x + 1) * 2) - 1
It looks like your loop is just reimplementing what reduce does. Here's a functional look at your function composition problem:
def compose1(fnlist):
if not fnlist:
return lambda x: x
# compose 1 function of x from two others
def compose2fns(fn1, fn2):
return lambda x : fn1(fn2(x))
# or if you really love lambdas
# compose2fns = lambda fn1,fn2: lambda x: fn1(fn2(x))
# use reduce to cumulatively apply compose2fns to the functions
# in the given list
return reduce(compose2fns, fnlist)
This passes your tests just fine.
CODE GOLF:
I couldn't resist, here is a one-liner, even including your check for an empty input list:
compose1 = lambda fnlist: reduce(lambda fn1,fn2: lambda x : fn1(fn2(x)),
fnlist or [lambda x:x])
Your issue here is your logic.
for i in range(len(lst)-2,-1,-1):
temp = lambda x: lst[i](temp)
return lambda x: temp
This will set temp to a function. lst is a list of functions, lst[i] is a function. You call that, to give a value, and then you make a new function with lambda. You then return a function that gives that function.
Your return value is a function, that gives a function, that gives a value, hence your issue.
As a note, this code has other problems. if lst == []: should be if not lst:, for example. You should also never iterate by index, and instead iterate by value, as Python is designed. I can't actually work out what you are trying to achieve with your code, which shows how hard to read iterating by index is.
Your code currently does this:
If there are no values, return a function that returns the first argument.
If there is one value, return the function in the list.
If there are many values, return a function that returns a function that returns the first value retrieved by running the first function from the list.
I'm not sure what you were trying to do, but I'm pretty sure that isn't it.
I like this syntax:
f = do (lambda x: x-1) (lambda x: x*2) (lambda x: x+1)
for x in range(10):
assert f(x) == 1 + (x - 1) * 2
The implementation is surprisingly trivial:
class do(object):
def __init__(self, x):
self.fns = [x]
def __call__(self, x):
if callable(x):
self.fns.append(x)
return self
for f in self.fns:
x = f(x)
return x
I'm having trouble with a question which follows: Write a recursive function repeatedlyApply that takes as arguments a function
f of one argument and a positive integer n. The result of repeatedlyApply is a function of one argument that applies f to that argument n times.
So, for example, we would have
repeatedlyApply(lambda x: x+1,10)(100) ==> 110
You may assume that the following function has been defined. You don't have to use it, but it can contribute to a pretty solution.
def compose(f,g):
return lambda x: f(g(x))
So far i've written this
def compose(f,g):
return lambda x: f(g(x))
def recApply(f,n):
for i in range(n):
return recApply(compose(f,f), n-1)
return f
I'm going wrong somewhere because using the above example recApply(lambda x: x+1,10)(100) i get 1124.
Help much appreciated
Correct answer is:
def recApply(func, n):
if n > 1:
rec_func = recApply(func, n - 1)
return lambda x: func(rec_func(x))
return func
And the output:
>>>> print recApply(lambda x: x+1,10)(100)
110
Your function needs some work:
You have a return inside your for loop, so you return immediately instead of running the loop.
You have a recursive call inside your for loop, so you are doing a bit too much iteration. Choose one or the other.
Be careful when you stack function compositions on top of each other, you are doing power composition rather than linear composition.
Can you tell us what precisely you are trying to do?
EDIT: Since everybody else is posting an answer:
recApply = lambda f, n: lambda x: x if n == 0 else recApply(f, n-1)(f(x))
I have a solution based on lambdas:
>>> f = lambda x: x + 10
>>> iterate = lambda f, n, x : reduce(lambda x, y: f(x), range(n), x)
>>> iterate(f, 10, 3)
103
>>> iterate(f, 4, 4)
44
>>> f10 = lambda x: iterate(f, 10, x)
>>> f10(5)
105
I assume this is an exercise of some sort. There are a few ways you could do it, here's a short one:
>>> repeatedlyApply = lambda f, n: reduce(lambda f1, f2: compose(f1, f2), [f]*n)
>>> repeatedlyApply(lambda x: x+1,10)(100)
110