How to achieve python's any() with a custom predicate? - python

>>> l = list(range(10))
>>> l
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> if filter(lambda x: x > 10, l):
... print "foo"
... else: # the list will be empty, so bar will be printed
... print "bar"
...
bar
I'd like to use any() for this instead, but any() only takes one argument: the iterable. Is there a better way?

Use a generator expression as that one argument:
any(x > 10 for x in l)
Here the predicate is in the expression side of the generator expression, but you can use any expression there, including using functions.
Demo:
>>> l = range(10)
>>> any(x > 10 for x in l)
False
>>> l = range(20)
>>> any(x > 10 for x in l)
True
The generator expression will be iterated over until any() finds a True result, and no further:
>>> from itertools import count
>>> endless_counter = count()
>>> any(x > 10 for x in endless_counter)
True
>>> # endless_counter last yielded 11, the first value over 10:
...
>>> next(endless_counter)
12

Use a generator expression inside of any():
pred = lambda x: x > 10
if any(pred(i) for i in l):
print "foo"
else:
print "bar"
This assumes you already have some predicate function you want to use, of course if it is something simple like this you can just use the Boolean expression directly: any(i > 10 for i in l).

Related

How do I get the output to only be numbers within a list that are greater than x?

def list_number(mylist,x):
y=[i if i>x else False for i in mylist]
return y
I am trying to get only the numbers that are greater than x in a list to be my output and I also need it to return False if there are no numbers greater than x.
For example mylist=[1,2,3,4,5,6,7,8,9] and x=5, I want my output to be [6,7,8,9].
if x=10, I want my output to be false.
I cannot use any methods like .append or .sort
The mistake in your example is your incorrect usage of list comprehension. Here are simple examples to show you how to use list comprehension with conditional statements:
iterator = range(10)
# Example (list comprehension with if statement)
[x for x in iterator if x > 5]
# [6, 7, 8, 9]
# Example (list comprehension with if...else statement)
[x if x > 5 else 0 for x in iterator]
# [0, 0, 0, 0, 0, 0, 6, 7, 8, 9]
As for your specific question, you can use the information above to create a function like this:
def list_number(mylist, x):
y = [n for n in mylist if n > x]
if not y:
return False
return y
You can use a list comprehension and then return False if the list is empty. Using the or operator allow it to simplify it as it will execute the second statement if the first one is considered as False, so if the list is empty.
def list_number(mylist, x):
return [y for y in mylist if y > x] or False
Another way it can be done is using a filter:
def list_number(mylist, x):
return list(filter(x.__lt__, mylist)) or False
x.__lt__ correspond to the less than operator on the value of x.
Either way,
>>> list_number(list(range(10)), 5)
[6, 7, 8, 9]
>>> list_number(list(range(10)), 11)
False
You can use the fact that empty list is a false value in python.
This way your code will always return a list, which is much better than returning a List | boolean
from typing import List
def list_number(my_list: List[int], x: int) -> List[int]:
return [num for num in my_list if num > x]
result: List[int] = list_number([4,6,89,21],7)
if(result):
print('non empty result')
else:
print('empty result')
result: List[int] = list_number([4,6,89,21],790)
if(result):
print('non empty result')
else:
print('empty result')
output
non empty result
empty result
I'd say this code is pretty easy to read and predictable. No need to have any advanced knowledge. (except typehints)
from typing import List, Union
l = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
x = 10
def greater_than(list_uf_nums: List[int], num: int) -> Union[List[int], bool]:
return_list = [y for y in list_uf_nums if y > num]
if not return_list:
return False
return return_list
print(greater_than(l, x))

Boolean values list to integer in Python

I'm having trouble with this lambdas syntax.
I'm trying to translate a list of booleans to an integer value, but I'm getting an error, I don't understand why.
Here is the code:
from functools import reduce
binary = [True, True, False, True]
L = list(range(len(binary))) #Step 1
print(L) #[0, 1, 2, 3]
L = map(lambda a: 2**a, L) #Step 2
print(L) #[1, 2, 4, 8]
L = zip(binary, L) #Step 3
print(L) #[(True, 1),(True, 2),(False, 4),(True, 8)]
L = filter(lambda a, b: a, L) #Step 4
print(L) #[(True, 1),(True, 2),(True, 8)] not sure
L = map(lambda a, b: b, L) #Step 5
print(L) #?????
L = reduce(lambda a, b: a + b, L) #Final step
print(L) #11
Output:
Traceback (most recent call last):
File "C:/Users/axel_/PycharmProjects/Python_Subject_Exam/19_new_exam_binary_list_translation.py", line 27, in <module>
L = reduce(lambda a, b: a + b, L)
TypeError: <lambda>() missing 1 required positional argument: 'b'
[0, 1, 2, 3]
<map object at 0x00000267FAFE5388>
<zip object at 0x00000267FAFE50C8>
<filter object at 0x00000267FAFE5248>
<map object at 0x00000267FAFE4EC8>
Process finished with exit code 1
Could anyone help me to debug?
I think this will solve your problem. I will write some comments in the code to help you understand:
from functools import reduce
binary = [True, True, False, True]
L = list(range(len(binary))) #[0, 1, 2, 3]
L = map(lambda a: 2**a, L) #[1, 2, 4, 8]
L = zip(binary, L) #[(True, 1), (True, 2), (False, 4), (True, 8)]
L = filter(lambda x: x[0], L) #<--- an item from zip() is an ((unpacked)) tuple
L = map(lambda x: x[1], L)
L = reduce(lambda a, b: a + b, L)
print(L) #11
This is one of the challenges if you are new to using iterators.
The iterator is evaluated as each item is pulled off the iterator, this means that when you call reduce to combine the result all of the lambda expressions are evaluated at that time. In your example this is equivalent to the following expression:
L = list(range(len(binary)))
L = reduce(lambda a, b: a + b,
map(lambda a, b: b,
filter(lambda a, b: a,
zip(binary,
map(lambda a: 2**a, L)
)
)
)
)
print(L)
Confusing?
In your example the line L = filter(lambda a, b: a, L) #Step 4 has an error. A filter expression takes a callable expression that takes a single argument along with an iterable but because it is not evaluated to the end you receive a confusing error.
One approach (and a good one when debugging) is to wrap each step in a call to list to force the evaluation to occur on each line eg L = list(filter(lambda a, b: a, L)). This will make the location of the error more apparent.
Alternatively use a generator expression rather than filter/map eg:
# filter (return odd numbers between 1 and 10)
result_a = filter(lambda a: a % 2, range(1, 11))
result b = (a for a in range(1, 11) if a % 2)
# map (return powers of 2)
result_a = map(lambda a: 2**a, range(11))
result_b = (2**a for a in range(11))
All of the results are the same but generator expressions have another trick, you can use tuple unpacking allowing for:
result = (b for a, b in zip(binary, range(len(binary))) if a)
Further, Python has other builtins that can simplify the code even more.
Enumerate will return a counter plus each element from an iterable allowing the first 3 steps to be simplified to:
# 1 step 1, 2 and 3 can be simplified with enumerate
L = ((i**2, b) for i, b in enumerate(L))
Next sum can be used to replace reduce, sum adds together all numerical values in an iterable:
L = reduce(lambda a, b: a + b, L)
# is equivalent to
L = sum(L)
And putting it all together the entire sequence can be simplified to:
L = sum(2**i for i, b in enumerate(binary) if b)
Hope that helps.

Find tuple structure containing an unknown value inside a list

Say I have list of tuples:
list = [(1,5), (1,7), (2,3)]
Is there a way in Python to write something like
if (1, *) in list: do things
where * means "I don’t care about this value"? So we are checking if there is a tuple with 1 at the first position and with whatever value on the second one.
As far as I know there are special mechanisms in other languages, but I just don’t know the name of this particular problem. So is there similar behavior in Python?
P.S.: I know that I can use list comprehensions here. I am just interested in this particular mechanism.
You can use the any() function:
if any(t[0] == 1 for t in yourlist):
This efficiently tests and exits early if 1 is found in the first position of a tuple.
A placeholder object like you're asking for isn't supported natively, but you can make something like that yourself:
class Any(object):
def __eq__(self, other):
return True
ANYTHING = Any()
lst = [(1,5), (1,7), (2,3)]
The __eq__ method defines how two objects test for equality. (See https://docs.python.org/3/reference/datamodel.html for details.) Here, ANYTHING will always test positive for equality with any object. (Unless that object also overrode __eq__ in a way to return False.)
The in operator merely calls __eq__ for each element in your list. I.e. a in b does something like:
for elem in b:
if elem == a:
return True
This means that, if you say (1, ANYTHING) in lst, Python will first compare (1, ANYTHING) to the first element in lst. (Tuples, in turn, define __eq__ to return True if all its elements' __eq__ return True. I.e. (x, y) == (a, b) is equivalent to x==a and y==b, or x.__eq__(a) and y.__eq__(b).)
Hence, (1, ANYTHING) in lst will return True, while (3, ANYTHING) in lst will return False.
Also, note that I renamed your list lst instead of list to prevent name clashes with the Python built-in list.
Not all of my solution methods provided below will be necessarily efficient. My goal is to demonstrate every possible solution method I can think of - at the end of my answer I provide "benchmark" results to show why or why not you should use one certain method over another. I believe that is a good way of learning, and I will shamelessly encourage such learning in my answers.
Subset + hash sets
>>> a_list = [(1,5), (1,7), (2,3)]
>>>
>>> set([l[0] for l in a_list])
{1, 2}
>>>
>>> 1 in set([l[0] for l in a_list])
True
map(), and anonymous functions
>>> a_list = [(1,5), (1,7), (2,3)]
>>>
>>> map(lambda x: x[0] == 1, a_list)
[True, True, False]
>>>
>>> True in set(map(lambda x: x[0] == 1, a_list))
True
filter and anonymous functions
>>> a_list = [(1,5), (1,7), (2,3)]
>>>
>>> filter(lambda x: x[0] == 1, a_list)
[(1,5), (1,7)]
>>>
>>> len(filter(lambda x: x[0] == 1, a_list)) > 0 # non-empty list
True
MICROBENCHMARKS
Conditions
1000 items
100K repetition
0-100 random range
Python 2.7.10, IPython 2.3.0
Script
from pprint import pprint
from random import randint
from timeit import timeit
N_ITEMS = 1000
N_SIM = 1 * (10 ** 5) # 100K = 100000
a_list = [(randint(0, 100), randint(0, 100)) for _ in range(N_ITEMS)]
set_membership_list_comprehension_time = timeit(
"1 in set([l[0] for l in a_list])",
number = N_SIM,
setup="from __main__ import a_list"
)
bool_membership_map_time = timeit(
"True in set(map(lambda x: x[0] == 1, a_list))",
number = N_SIM,
setup="from __main__ import a_list"
)
nonzero_length_filter_time = timeit(
"len(filter(lambda x: x[0] == 1, a_list)) > 0",
number = N_SIM,
setup="from __main__ import a_list"
)
any_list_comprehension_time = timeit(
"any(t[0] == 1 for t in a_list)",
number = N_SIM,
setup="from __main__ import a_list"
)
results = {
"any(t[0] == 1 for t in a_list)": any_list_comprehension_time,
"len(filter(lambda x: x[0] == 1, a_list)) > 0": nonzero_length_filter_time,
"True in set(map(lambda x: x[0] == 1, a_list))": bool_membership_map_time,
"1 in set([l[0] for l in a_list])": set_membership_list_comprehension_time
}
pprint(
sorted(results.items(), key = lambda x: x[1])
)
Results (in seconds)
[('any(t[0] == 1 for t in a_list)', 2.6685791015625), # winner - Martijn
('1 in set([l[0] for l in a_list])', 4.85234808921814),
('len(filter(lambda x: x[0] == 1, a_list)) > 0', 7.11224889755249),
('True in set(map(lambda x: x[0] == 1, a_list))', 10.343087911605835)]
Who's got the last laugh now? ... Martijn (at least I tried)
MORAL OF THE STORY: Don't spend more than 10 minutes "proving" your inferior solution is faster and more efficient on a small test data, when another user's answer is the de-facto correct one
This can be done in Python using list comprehension.
ex:
a= [(1, 2), (3, 4), (4, 5), (1, 4)]
[i for i in a if i[0] == 1]
Will give you:
[(1, 2), (1, 4)]
Indexing is the simplest but if you wanted to use syntax similar to your example where you wanted to assign the first value to a variable and ignore the rest you could use python3's extended iterable unpacking.
In [3]: [a for a,*_ in l]
Out[3]: [1, 1, 2]
Or with the any logic:
In [4]: l = [(1,5), (1,7), (2,3)]
In [5]: any(a == 1 for a,*_ in l)
Out[5]: True
Or mimicking any without the function call:
In [23]: l = [(1,5), (1,7), (2,3)]
In [24]: g = (a for a,*_ in l)
In [25]: 1 in g
Out[25]: True
In [26]: list(g)
Out[26]: [1, 2]
number of element in tuple could be handled also.
>>> import operator
>>> mylist = [(1,2), (1,5), (4,5,8)]
>>> any(i==1 for i in map(operator.itemgetter(0), mylist))
True
It sounds like you actually want filter(), not any():
tuple_list = [(1,5), (1,7), (2,3)]
for pair in filter(lambda pair: (pair[0] == 1), tuple_list):
print "Second value {pair[1]} found from {pair}".format(pair=pair)
...
Second value 5 found from (1, 5)
Second value 7 found from (1, 7)
The filter() method is great because you can provide a function directly to it. This lets you specify a certain key to filter on, etc. To simplify it further, use a lambda expression to make the entire thing into a one-liner.

How list comprehensions are evaluated in python and in what order

I have two list comprehensions where conditions are defined in different places.
>>> [ x**2 if x%2==0 else x**3 if x%3==0 else 0 for x in range(10)]
[0, 0, 4, 27, 16, 0, 36, 0, 64, 729]
>>> [ x**2 if x%2==0 for x in range(10) ]
File "<stdin>", line 1
[ x**2 if x%2==0 for x in range(10) ]
^
SyntaxError: invalid syntax
However if i do this:
>>> [ x**2 for x in range(10) if x%2==0 ]
[0, 4, 16, 36, 64]
>>>
it works.
Now the confusing part is how the order is evaluated. What is the difference?
You have two different concepts confused here.
An expression like x**2 if x%2==0 else x**3 is a conditional expression. They can be chained, but the else is not optional - because this is a self-contained expression that evaluates to a single, specific value. The else x**3 is required because Python has to know what the expression evaluates to whenever it is not the case that x % 2 == 0.
In a list comprehension, when you write things like [x**2 for x in range(10) if x%2==0], the if clause is used to filter the x values found in range(10), for which elements of the resulting list are computed. There is no else permitted here because the purpose is entirely different.
You can mix and match: [x**2 if x%2 == 0 else x**3 for x in range(10) if x%3 == 0]. Now if x % 3 == 0 is being used to decide which x values to compute a result for, and if x%2 == 0 is being used to decide whether to use x**2 or x**3 as the computed result for those xs.
You are confusing two completely different constructs.
Conditions for list comprehensions can be defined only at one plance, at the end, and they act like filters:
[ ... for ... if .... ]
The other construct you see is python's version of the ternary operator. It's not a filter, it just selects one of the expressions based on the logical value of a third expression:
... if ... else ...
from the docs:
A list comprehension consists of brackets containing an expression
followed by a for clause, then zero or more for or if clauses. The
result will be a new list resulting from evaluating the expression in
the context of the for and if clauses which follow it.
so, by definition the if comes after the for.
For example, this:
[ x**2 if x%2==0 else x**3 if x%3==0 else 0 for x in range(10)]
Is the equivalent of this:
>>> l = []
>>> for x in range(10):
... l.append(x**2 if x%2==0 else x**3 if x%3==0 else 0)
...
>>> l
[0, 0, 4, 27, 16, 0, 36, 0, 64, 729]
I.e. there is no if statement, but rather an if expression. So there's always something appended to the list on every step of the for.
However when you do this:
[ x**2 for x in range(10) if x%2==0 ]
And if statement will be used. And not all steps will append to the list. Translated into:
>>> l = []
>>> for x in range(10):
... if x%2==0:
... l.append(x**2)
...
>>> l
[0, 4, 16, 36, 64]

python last element change to different format

i have a list such as this 1,2,3,4,5,6,7,8,9,10. I want to loop through it with python code, and properly format it to 1,2,3,4,5,6,7,8,9,10. The following is the code that i am using to execute the loop
lst = [1,2,3,4,5,6,7,8,9,10]
for x in lst:
print "%s,"%x
This is the return value
1,2,3,4,5,6,7,8,9,10,
Can python pick up the last element of the loop and change the format of the loop?
You can use join but you will need to change the ints to strings:
print ','.join(str(x) for x in lst)
You can specify a separator and join the list:
print ", ".join(str(x) for x in lst)
Also, I recommend not hiding the builtin name list and call your numbers something else.
If you want to explicitly loop through it, and not print the space:
import sys
my_list = range(1,10+1) 
for x in my_list:
sys.stdout.write("%s," % x)
or
>>> my_list = range(1,10+1)
>>> print ','.join(map(str, my_list)) + ','
where the last + ',' is necessary to have a comma at the very end.
The word list is a builtin in python, so you should avoid naming variables list as that will remove the keyword from the namespace.
>>> a = (1,2,3)
>>> print a
(1, 2, 3)
>>> print list(a)
[1, 2, 3]
>>> type(a) == list
False
>>> type(list(a)) == list
True
Just for fun:
>>> lst = [1,2,3,4,5,6,7,8,9,10]
>>> str(lst)[1:-1]
'1, 2, 3, 4, 5, 6, 7, 8, 9, 10'

Categories

Resources