I have function f that takes int and return bool. I want to find minimum non-negative integer x, for which f(x) is False. How can I do it in most pythonic way (ideally one line)?
Here is how I do it now:
x = 0
while f(x):
x += 1
print(x)
I want something like:
x = <perfect one line expression>
print(x)
Here it is, using next:
from itertools import count
x = next(i for i in count() if not f(i))
Demo:
>>> def f(x):
... return (x - 42)**2
...
>>> next(i for i in count() if not f(i))
42
A similar functional approach with itertools.filterfalse and itertools.count could be
from itertools import filterfalse, count
x = next(filterfalse(f, count()))
Or you can swap out filterfalse with dropwhile, which while performantly similar maintains the same syntax across Python 2 and 3 (thanks to rici).
from itertools import dropwhile, count
x = next(dropwhile(f, count()))
If you'd like a single line without imports, one way might be a list comprehension (Python 2.7 / PyPy):
def f(x):
return True if x == 5 else False
x = [g(0) for g in [lambda x: x if f(x) else g(x+1)]][0]
print(x)
Related
What's the pythonic way to combine a list of lambdas in a single function? For example:
lambdas = [lambda x, k=k: x+k for k in range(3)]
I would like to get this all in a single lambda similar to this but without having to type it out:
f = lambda x: lambdas[2](lambdas[1](lambdas[0](x)))
You can do this with functools.reduce like below:
from functools import reduce
lambdas = [lambda x, k=k: x+k for k in range(3)]
# x = 0
reduce(lambda x, l: l(x), lambdas, x)
# -> l[2](l[1](l[0](x)))
# step_1 : x = x , l = lambda[0] -> lambda[0](x)
# step_2 : x = lambda[0](x), l = lambda[1] -> lambda[1](lambda[0](x))
# step_3 : x = lambda[1](lambda[0](x)), l = lambda[2] -> lambda[2](lambda[1](lambda[0](x)))
The reduce function is defined to be exactly what you want. An alternative is to use a simple for loop.
def f(x):
for func in lambdas:
x = func(x)
return x
to do this with a lambda seems kind of weird.
Is there any specific reason why we cannot:
def function_chainer(lambdas):
def chained(x):
for function in lambdas:
x = function(x)
return chained
This solution is not a one-liner, but it is pythonic I believe.
If you really need a one-liner, you can use functools.reduce:
lambda x: functools.reduce(lambda a, f: f(a), lambdas, x)
The first argument to reduce governs the way of applying each subsequent element, the second is the iterable (here - our iterable of lambdas) and the last one is the initializer - the first value we want to pass to those lambda functions.
Hi I'm trying to write a function to find the factorial product of any given number. For example for factorial (6) I would get the product of 6*5*3*2*1.
so for factorial(3) the output would be 6.
The functions I have so far are:
import functools
def mult(x, y):
return x * y
def factorial(n):
if n == 0:
return 1
else:
functools.reduce(mult(n,factorial(n - 1)))
But I keep getting an error that Python is expecting 2 arguments and 1 is given. I know I have to use range somehow but I can't figure it out. How do I edit my existing code so that it runs properly?
you can do this pretty easily:
>>> import functools, operator
>>> functools.reduce(operator.mul, xrange(1, 6))
120
Note that the first argument is a function (you're passing the result of a function call). the second argument is an iterable. Also note that written this way, no recursion is needed...
operator.mul is equivalent to your mult function
import functools
def factorial(n):
if n == 0:
return 1
else:
return functools.reduce(lambda x,y: x*y, range(1,n+1))
print factorial(3)
Of course you can use you own multi function instead of the lambda if you prefer.
>>> x = 8
>>> reduce(lambda x,y: x*y, [1, 1] if x == 0 else xrange(1, x+1))
n = int(input())
import functools
def factorial(n):
if n == 0:
return 1
else:
return functools.reduce(lambda x,y: x*y , range(1,n+1))
print(factorial(n))
output:-
Input
3
Solution output
6
If you are using 2.7, then I would reccomend looking here at the documentation for reduce. If you are using 3, then we see that
functools.reduce is the same as 2.7's reduce
That is, we see that we need to call functools in the same way as in 2.7. The following is a representation of that:
reduce(lambda x, y: x+y, [1, 2, 3, 4, 5])
, which translates to:
functools.reduce(lambda x, y: x+y, [1, 2, 3, 4, 5])
For the case of your example, you are making your own operator, which is confusing reduce. This can be solved by adding import operator , and then using the methods that are declared that are defined in operator (i.e. operator.add).
I hope this helps clear things up!
from functools import reduce
f=lambda x,y:x*y
def factorial(number):
if(number==1):
return 1
else:
return reduce(f,range(1,number+1))
print(factorial(n))
Here is a perfect snippet for the factorial function using a reduce built-in function. This will print 1 when n=0, as the factorial of 0 is 1.
# Read the input as an integer
n = 4
# Import the reduce() function
from functools import reduce
fact = lambda x,y:x*y
print(1 if n == 0 else reduce(fact,range(1,n+1)))
My solution:
from functools import reduce
list_num = list(range(1,8,1)) # instead of 8 put the number+1 of which you need factorial
def fact_num(acc, item):
return acc*item
print(reduce(fact_num, list_num,1))
from functools import reduce
n = int(input("Enter a number: "))
print("Factorial is:", reduce(lambda x, y: x*y, range(1, n+1)))
n = int (input ("Enter a natural number "))
n_list = range(1,n+1)
from functools import reduce
factorial = reduce(lambda x,y: x*y, n_list) factorial
-----Import the reduce() function
from functools import reduce
---Read the input as an integer
n = int(input())
fact=reduce(lambda x,y:x+y,range(n+1))
print(fact)
I have a generator and would like to find out what the first value which it generates larger than X. One way to do this is as follows, but it seems rather long-winded (it reads like it repeats itself).
def long_winded(gen,X)
n = next(gen)
while n < X: n=next(gen)
return n
What I wanted to write was something more simply:
short_broken(gen,X):
while next(gen)<X: pass
return next(gen) # returns the SECOND value larger than X, as gen is called again
short_broken2(gen,X):
while n = next(gen)<X: pass # Not python syntax!
return n
Is there a pythonically-concise way to return the same result?
from itertools import dropwhile
def first_result_larger_than_x(gen, X):
return next(dropwhile(lambda n: n <= X, gen))
Note that your code examples from the OP are actually returning the first result greater than or equal to X. I've corrected that in this code example, but if that was what you actually wanted, change the <= to a <.
def short2(gen,X):
for x in gen:
if x > X:
return x
or as a 1-liner (which I prefer to the itertools variant):
def short3(gen,X):
return next(x for x in gen if x > X)
my original answer -- left only for the sake of posterity
I'm not necessarily asserting that this method is better, but you can use a recursive function:
def short(gen,X):
n = next(gen)
return n if n>X else short(gen,X)
I'm trying to write a function in python that is like:
def repeated(f, n):
...
where f is a function that takes one argument and n is a positive integer.
For example if I defined square as:
def square(x):
return x * x
and I called
repeated(square, 2)(3)
this would square 3, 2 times.
That should do it:
def repeated(f, n):
def rfun(p):
return reduce(lambda x, _: f(x), xrange(n), p)
return rfun
def square(x):
print "square(%d)" % x
return x * x
print repeated(square, 5)(3)
output:
square(3)
square(9)
square(81)
square(6561)
square(43046721)
1853020188851841
or lambda-less?
def repeated(f, n):
def rfun(p):
acc = p
for _ in xrange(n):
acc = f(acc)
return acc
return rfun
Using reduce and lamba.
Build a tuple starting with your parameter, followed by all functions you want to call:
>>> path = "/a/b/c/d/e/f"
>>> reduce(lambda val,func: func(val), (path,) + (os.path.dirname,) * 3)
"/a/b/c"
Something like this?
def repeat(f, n):
if n==0:
return (lambda x: x)
return (lambda x: f (repeat(f, n-1)(x)))
Use an itertools recipe called repeatfunc that performs this operation.
Given
def square(x):
"""Return the square of a value."""
return x * x
Code
From itertools recipes:
def repeatfunc(func, times=None, *args):
"""Repeat calls to func with specified arguments.
Example: repeatfunc(random.random)
"""
if times is None:
return starmap(func, repeat(args))
return starmap(func, repeat(args, times))
Demo
Optional: You can use a third-party library, more_itertools, that conveniently implements these recipes:
import more_itertools as mit
list(mit.repeatfunc(square, 2, 3))
# [9, 9]
Install via > pip install more_itertools
Using reduce and itertools.repeat (as Marcin suggested):
from itertools import repeat
from functools import reduce # necessary for python3
def repeated(func, n):
def apply(x, f):
return f(x)
def ret(x):
return reduce(apply, repeat(func, n), x)
return ret
You can use it as follows:
>>> repeated(os.path.dirname, 3)('/a/b/c/d/e/f')
'/a/b/c'
>>> repeated(square, 5)(3)
1853020188851841
(after importing os or defining square respectively)
I think you want function composition:
def compose(f, x, n):
if n == 0:
return x
return compose(f, f(x), n - 1)
def square(x):
return pow(x, 2)
y = compose(square, 3, 2)
print y
Here's a recipe using reduce:
def power(f, p, myapply = lambda init, g:g(init)):
ff = (f,)*p # tuple of length p containing only f in each slot
return lambda x:reduce(myapply, ff, x)
def square(x):
return x * x
power(square, 2)(3)
#=> 81
I call this power, because this is literally what the power function does, with composition replacing multiplication.
(f,)*p creates a tuple of length p filled with f in every index. If you wanted to get fancy, you would use a generator to generate such a sequence (see itertools) - but note it would have to be created inside the lambda.
myapply is defined in the parameter list so that it is only created once.
I should write a function min_in_list(munbers), which takes a list of
numbers and returns the smallest one. NOTE: built-in function min is NOT allowed!
def min_in_list(numbers):
the_smallest = [n for n in numbers if n < n+1]
return the_smallest
What's wrong?
def min_of_two(x, y):
if x >= y: return x
else: return y
def min_in_list(numbers):
return reduce(min_of_two, numbers)
You have to produce 1 number from list, not just another list. And this is work for reduce function (of course, you can implement it without reduce, but by analogy with it).
Here you go. This is almost certainly about as simple as you could make it. You don't even have to give me credit when you turn the assignment in.
import itertools
import functools
import operator
def min(seq, keyfun=operator.gt):
lt = lambda n: functools.partial(keyfun, n)
for i in seq:
lti = lt(i)
try:
next(itertools.ifilter(lti, seq))
except:
return i
min = lambda n: return reduce(lambda x,y: (x>y) and return x or return y,n)
Never been tested, use at your own risk.