This question already has answers here:
How to achieve python's any() with a custom predicate?
(2 answers)
Closed 6 years ago.
I am trying to find out if there are any built-in tools in Python that work the same way any() and all() are implemented, but instead of checking if each element is truthy or falsy, you can pass your own boolean-evaluating function or lambda, sort of like you can do with the map() function.
So what I'm asking is if there are any built-in functions where you could do something like:
from random import randint
lst = [randint(1, 100) for _ in range(1000000)]
has_even = any(lambda x: not x % 2, lst)
or
has_even = any(has_even_fn, lst)
where has_even_fn would be a function that checked if an integer is even.
You can still use any() to check if lst has evens:
has_even = any([not x % 2 for x in lst])
But of course this is strictly O(n) because the entire boolean list has to be built first, while the function I am asking for would only be O(n) in the worst case, and potentially O(1) in the best case.
As already stated in the comments, you can just remove the [ ] to get a lazy-evaluating generator expression instead of an eager list comprehension:
contains_one_or_more_even = any(x % 2 == 0 for x in lst)
or
contains_only_even = all(x % 2 == 0 for x in lst)
Related
def anagramwordchecker(z,w):
if sorted([x for x in w])==sorted([x for x in z]):return True
return False
def anagramlistchecker(l,w):
d={}
for x in w:
d.update({x:w.count(x)})
l=list(filter(lambda x:anagramwordchecker(x,w),l))
return l
print(anagramlistchecker(['bcda', 'abce', 'cbda', 'cbea', 'adcb'],'abcd'))
trying to check which words are anagram.
using both of this it will print the same:
l=[x for x in l if anagramwordchecker(x,w)]
l=list(filter(lambda x:anagramwordchecker(x,w),l))
and it will be:
['bcda', 'cbda', 'adcb']
then what's the difference? any advantage using filter? cause comprehension is easier.
If you print the results of the following example, you will know which one is faster (Comments are results I got).
timeit.Timer('''[x for x in range(100) if x % 2 == 0]''' ).timeit(number=100000)
timeit.Timer('''list(filter(lambda x: x % 2 == 0, range(100)))''').timeit(number=100000)
# 0.3664856200000486
# 0.6642515319999802
So in your case, list comprehension would be faster. But let's see the following example.
timeit.Timer('''[x for x in range(100) if x % 2 == 0]''' ).timeit(number=100000)
timeit.Timer('''(x for x in range(100) if x % 2 == 0)''' ).timeit(number=100000)
timeit.Timer('''filter(lambda x: x % 2 == 0, range(100))''').timeit(number=100000)
# 0.5541256509999357
# 0.024836917000016
# 0.017953075000036733
The results show that casting an iterable to list takes much time and filter is faster than generator expression. So if your result does not really have to be a list, returning an iterable in a timely manner would be better.
As stated in here,
Note that filter(function, iterable) is equivalent to the generator expression (item for item in iterable if function(item)) if function is not None and (item for item in iterable if item) if function is None.
But list comprehension can do much more than simply filtering. If filter is given to the interpreter, it will knows it is a filter function. However, if a list comprehension is given to the interpreter, the interpreter does not know what it really is. After taking some time interpreting the list comprehension to something like a function, it would be a filter or filterfalse function in the end. Or, something else completely different.
filter with not condition can do what filterfalse does. But filterfalse is still there. Why? not operator does not need to be applied.
There is no magic. Human-friendly 1-for-many grammars are based on encapsulation. For them to be machine-executable binaries, they need to be decapsulated back and it takes time.
Go with a specific solution if it is enough than taking a more general solutions. Not only in coding, general solutions are usually for convenience, not for best results.
I came across a solution on Stack Overflow to generate prime numbers using list comprehension. But was unable to understand what does the inner for loop do.
I have tried something like
[x for x in range(5,20) for y in range(2,int(x/2)+1) if any(x%y == 0)]
It throws an error: 'bool' object is not iterable
I know that my syntax is wrong but logically for prime numbers we have a for loop followed by a for loop and then a if condition to calculate remainder(x%y).
But the answer on Stack Overflow is
[x for x in range(2, 20) if all(x % y != 0 for y in range(2, x))]
I understood the reason why all is used, but I am unable to get how the condition inside all() is working as ideally for should be following if so that range(2,x) is iterated and y gets values which are in turn used for computing(x%y). How can y be used even before it is has been assigned a value.
That is just the wonderful thing about list comprehension if it can work normally like the for loop, people wont create it because the for loop is more readable and understandable.
You may find out that the result of list comprehension is always a list, meanwhile the result of for loop would always many single values and these single values is a part of iterable
[x +1 for x in range(1,5)]
[2, 3, 4, 5]
for x in range (1,10): print(x+1)
2
3
4
5
You can simply understand that the loop comprehension already have the list of values, then they just simply feed orderly to the condition value by value. Like this:
[1+1 , 2+1 , 3+1 , 4+1]
Your code is wrong because you inherit too much from the ordinary for loop. Your code written in for loop would be like this:
for x in range(5,20):
for y in range(2,int(x/2)+1):
if any(x%y == 0):
print(x)
And the result would obviously:
TypeError: 'bool' object is not iterable
because any requires an iterable such as a generator expression or a **list** as mentioned above by #meowgoesthedog . Coincidentally, list is just all about list comprehension. However, you need comprehend it in order to utilize the list comprehension well. It sometimes happens to me too, in your case, the for y in range(2,int(x/2)+1) works as a normal for loop.
This is the syntax of list comprehension.
In side the condition if which is optional predicate. We can create another list comprehension by following the rules with x%y==0 is output expression and a variable y representing members of the input sequence range(2,int(x/2)+1)
all() and any() works on itterable objects. For example all([True, True, False, True]) returns False. You cant use any(True) (like in your example: any(x%y == 0))
This statement [x for x in range(2, 20) if all(x % y != 0 for y in range(2, x))] can be translated to this code:
res = []
for x in range(2, 20):
temporary_list = (x%y != 0 for y in range(2,x))
if all(temporary_list):
res.append(x)
Ps. I saw in comments that you are not sure how y is declared. In python, there are more great structures than list of comprehension. One of them is generator of comprehension - I believe it is used in this case.
The syntax all and any work on iterable objects (list, sets, etc). Therefore you get an error when you apply it on boolean - x%y==0.
You can use any in the following manner -
[x for x in range(5,20) if not any([x % y == 0 for y in range(2, int(x/2)+1)])]
or -
[x for x in range(2, 20) if not any(x % y == 0 for y in range(2, int(x/2)+1))]
As any and all complement each other.
This question already has answers here:
Creating functions (or lambdas) in a loop (or comprehension)
(6 answers)
Closed 5 years ago.
I tried to achieve something like this
list1 = [lambda x: x+0, lambda x: x+1]
by doing this
list2 = [lambda x: x+n for n in range(2)]
But it doesn't work! (Why not?)
How do I create a list of functions programmatically?
n is reassigned by the for expression, so after the for expression is completed both will see value of n being 1.
More typical example of this problem can be visible without list expression:
list3 = []
for n in range(2):
def f(x):
return x + n
list3.append(f)
Here also all created function objects will refer to the same variable n and it will be assigned value 1 and both function objects will work as lambda x: x + 1.
You can deal with it by creating additional scope with a variable for each created function:
a = [(lambda n: lambda x: x+n)(n) for n in range(2)]
Both code examples below are old examples of a problem I have where I am iterating through a list of numbers to find numbers that fit a list of conditions but couldn't find a neat way to express it except for:
condition1 and condition2 and condition3 and condition4 and condition5
Two examples of the above:
if str(x).count("2")==0 and str(x).count("4")==0 and str(x).count("6")==0 and str(x).count("8")==0 and str(x).count("0")==0:
if x % 11==0 and x % 12 ==0 and x % 13 ==0 and x%14==0 and x %15 == 0 and x%16==0 and x%17==0 and x%18==0 and x%19==0 and x%20==0:
Is there a simple, more neat way of doing this?
My first retry was to store the conditions in a list like below:
list=["2","4","6","8","0"]
for element in list:
#call the function on all elements of the list
list=[11,12,13,14,15,16,17,18,19,20]
for element in list:
#call the function on all elements of the list
but I was hoping for an even neater/simpler way.
You can use a generator expression like this
def f(n):
return x%n
if all(f(element) for element in lst):
...
If the function/calculation is not too complex, you can just put it inline
if all(x % element for element in lst):
...
The built in function all can simplify this, if you can express your conditions in a generator expression:
result = all(x % n == 0 for n in xrange(11, 21))
It returns a boolean result indicating whether or not all the elements of its iterable argument are True, short-circuiting to end evaluation as soon as one is False.
This is the second question I've seen in the last hour or so for which all is the answer - must be something in the air.
This question already has answers here:
In Python what's some other ways to write a if x==1 or x==5 or x==10...?
(3 answers)
Closed 9 years ago.
Take for example this code:
if int(str(x)[len(str(x)) - 1]) == 0 or int(str(x)[len(str(x)) - 1]) == 5:
return False
Supposing I have even a bigger list of or's, is there an easier way of doing this?
Ok, now that I know to use if x in ( , , , etc), how do I implement this into this:
filter(lambda x: int(str(x)[len(str(x)) - 1]) in (0, 5), range(1000)) Got it, wrong parenthesis, bad python programmer.
The simplest way is like this:
if x in (2,3):
....
If you have a large number of candidate values, then this will result in a linear search which could be expensive. If that matters then a set could result in better performance:
if x in set((2,3)):
....
Note that any performance benefit from using a set could only come if the set could be instantiated once, but tested for membership multiple times.
myset = set((2,3))
....
if x in myset:
....
It looks to me that you are actually testing divisibility by 5 which can be done like this:
if x % 5 == 0:
....
Use the ´in´ operator:
if x in (2, 3):
pass
Does this work?
if int(str(x)[-1]) in (0,5):
return False
Note that some_array[-1] returns the last element in some_array so that you don't have to do some_array[len(sum_array) - 1]