rewrite small piece of python code - python

I have lots of small pieces of code that look like:
for it in <iterable>:
if <condition>:
return True/False
Is there a way I can rewrite this piece of code with a lambda expression ? I know I can factor it out in a small method/function, but I am looking for some lambda thing if it can be done.

Use the built-in any function.
e.g.
any(<condition> for it in <iterable>) # return True on <condition>

In addition to what everyone else has said, for the reverse case:
for it in <iterable>:
if <condition>:
return False
return True
use all():
b = all(<condition> for it in <iterable>)

if you want to check the condition for every item of iterable you can use
listcomprehensions to to this
b = [ x == whatever for x in a ]
you can combine this with any if you only need to know if there is one element
that evals to true for your condition
b = any(x == whatever for x in a)

Here is a simple example which returns True if any of the objects in it is equal to 2. by using the map function:
any(map(lambda x: x==2, it))
Change the lambda expression to reflect your condition.
Another nice way is to use any with a list comprehension:
any([True for x in it if x==2])
or alternatively, a generator expression:
any(x==2 for x in it)

Related

Python: general iterator or pure function for testing any condition across list

I would like to have a function AllTrue that takes three arguments:
List: a list of values
Function: a function to apply to all values
Condition: something to test against the function's output
and return a boolean of whether or not all values in the list match the criteria.
I can get this to work for basic conditions as follows:
def AllTrue(List, Function = "Boolean", Condition = True):
flag = True
condition = Condition
if Function == "Boolean"
for element in List:
if element != condition:
flag = False
break
else:
Map = map(Function, List)
for m in Map:
if m != condition:
flag = False
break
return flag
Since python doesn't have function meant for explicitly returning if something is True, I just make the default "Boolean". One could clean this up by defining TrueQ to return True if an element is True and then just mapping TrueQ on the List.
The else handles queries like:
l = [[0,1], [2,3,4,5], [6,7], [8,9],[10]]
AllTrue(l, len, 2)
#False
testing if all elements in the list are of length 2. However, it can't handle more complex conditions like >/< or compound conditions like len > 2 and element[0] == 15
How can one do this?
Cleaned up version
def TrueQ(item):
return item == True
def AllTrue(List, Function = TrueQ, Condition = True):
flag = True
condition = Condition
Map = map(Function, List)
for m in Map:
if m != condition:
flag = False
break
return flag
and then just call AllTrue(List,TrueQ)
Python already has built-in the machinery you are trying to build. For example to check if all numbers in a list are even the code could be:
if all(x%2==0 for x in L):
...
if you want to check that all values are "truthy" the code is even simpler:
if all(L):
...
Note that in the first version the code is also "short-circuited", in other words the evaluation stops as soon as the result is known. In:
if all(price(x) > 100 for x in stocks):
...
the function price will be called until the first stock is found with a lower or equal price value. At that point the search will stop because the result is known to be False.
To check that all lengths are 2 in the list L the code is simply:
if all(len(x) == 2 for x in L):
...
i.e. more or less a literal translation of the request. No need to write a function for that.
If this kind of test is a "filter" that you want to pass as a parameter to another function then a lambda may turn out useful:
def search_DB(test):
for record in database:
if test(record):
result.append(record)
...
search_DB(lambda rec: all(len(x) == 2 for x in rec.strings))
I want a function that takes a list, a function, and a condition, and tells me if every element in the list matches the condition. i.e. foo(List, Len, >2)
In Python >2 is written lambda x : x>2.
There is (unfortunately) no metaprogramming facility in Python that would allow to write just >2 or things like ยท>2 except using a string literal evaluation with eval and you don't want to do that. Even the standard Python library tried going down that path (see namedtuple implementation in collections) but it's really ugly.
I'm not saying that writing >2 would be a good idea, but that it would be nice to have a way to do that in case it was a good idea. Unfortunately to have decent metaprogramming abilities you need a homoiconic language representing code as data and therefore you would be programming in Lisp or another meta-language, not Python (programming in Lisp would indeed be a good idea, but for reasons unknown to me that approach is still unpopular).
Given that, the function foo to be called like
foo(L, len, lambda x : x > 2)
is just
def foo(L, f=lambda x : x, condition=lambda x: x):
return all(condition(f(x)) for x in L)
but no Python programmer would write such a function, because the original call to foo is actually more code and less clear than inlining it with:
all(len(x) > 2 for x in L)
and requires you to also learn about this thing foo (that does what all and a generator expression would do, just slower, with more code and more obfuscated).
You are reinventing the wheel. Just use something like this:
>>> l = [[0,1], [2,3,4,5], [6,7], [8,9],[10]]
>>> def all_true(iterable, f, condition):
... return all(condition(f(e)) for e in iterable)
...
>>> def cond(x): return x == 2
...
>>> all_true(l, len, cond)
False
You can define a different function to check a different condition:
>>> def cond(x): return x >= 1
...
>>> all_true(l, len, b)
True
>>>
And really, having your own function that does this seems like overkill. For example, to deal with your "complex condition" you could simply do something like:
>>> l = [[0,2],[0,1,2],[0,1,3,4]]
>>> all(len(sub) > 2 and sub[0] == 5 for sub in l)
False
>>> all(len(sub) > 1 and sub[0] == 0 for sub in l)
True
>>>
I think the ideal solution in this case may be:
def AllTrue(List, Test = lambda x:x):
all(Test(x) for x in List)
This thereby allows complex queries like:
l = [[0, 1], [1, 2, 3], [2, 5]]
AllTrue(l, lambda x: len(x) > 2 and x[0] == 1)
To adhere to Juanpa's suggestion, here it is in python naming conventions and an extension of what I posted in the question now with the ability to handle simple conditions like x > value.
from operator import *
all_true(a_list, a_function, an_operator, a_value):
a_map = map(a_function, a_list)
return all( an_operator(m, a_value) for m in a_map)
l = [[0,2],[0,1,2],[0,1,3,4]]
all_true(l, len, gt, 2)
#True
Note: this works for single conditions, but not for complex conditions like
len > 2 and element[0] == 5

Python does not allow multiple return() statements in ternary; possible alternative that is also aesthetically pleasing?

I am developing a text based RPG (graphics will be implemented later) and I am writing a method to determine whether a room a player is trying to go to exists or not. In this method I have multiple logic statements that determine what room the player is trying to get to based on the direction they enter and whether that "room" == 0 (my place holder for an empty space in the world/dungeon array). Although I can write a conventional logic statement for this:
if condition:
if otherCondition:
return(True)
else:
return(False)
a ternary is much more aestheticaly pleasing:
if condition:
return(True) if otherCondition else return(False)
But of course, that does not work. I am looking for something that functions as the conventional logic statement but is also "pleasing to the eye", like a ternary. In my code the logic statement is repeated four times, and the conventional logic statement would be displeasing to read.
I am using Python 3.5.1 on Windows 7.
The issue with your statement isn't the ternary part, it's the repeated return. Instead use:
if condition:
return True if otherCondition else False
Here, the result of the expression True if otherCondition else False is returned.
This could be written more concisely as:
if condition:
return bool(otherCondition)
Use just a single return with ternary statement:
return 'something' if someCondition else 'something else'
For you case is enough just :
if condition:
return otherCondition
# or if "otherCondition is not bool you can use: return bool(condition)
z = x if success else y
# this tallies z = success ? x : y, where success is a bool. Either True or False
Here the expression on the right returns x or y depending on if success evaluates to True or False respectively. As this is an expression it can be used with a return statement
return x if success else y
if condition:
return othercondition
Perhaps you should illustrate with an example, because it can be simplified to return the result of the other condition.
if condition:
return otherCondition
What ever happened to just:
if condition:
# tis very simple; if room is equal to 0, the operation is true, thus `True` will be returned
# otherwise `False`.. no mystery
return room == 0

Is there a way to use an if statement as an argument?

Is it possible to use an if statement as an argument for another if statement ?
Like if one if statement is correct then the other if statement does this, but i'm not talking about nested ifs. Like if you have 3 if statements,
Is it possible to say if all those 3 are true then do this, or if all 3 of them are false then do this?
That's what a logical statement is for:
if condition1 and condition2 and condition3:
# do something if all three are true
else:
# not all three are true
If you have a variable number of elements to test, you could use all():
if all(conditions):
or with a generator expression:
if all(val == testvale for val in sequence_of_values):
Any of these expressions can be stored in a variable first:
list_of_conditions = [condition1, condition2, condition3]
if some_fourth_condition and all(list_of_conditions):
but then you lose the short-circuiting behaviour of the and operand; all 3 condition expressions will be evaluated to build list_of_conditions, while and won't evaluate the right-hand expression if the left-hand expression resolved to a false value.
Last, but not least, there is the conditional expression, which returns the outcome of one of two expressions based on an boolean test:
outcome = true_expression if test_expression else false_expression
and only one of true_expression or false_expression will actually be evaluated based on the outcome of test_expression.
I think you mean and:
if <condition1> and <condition2> and <condition3>:
# All three conditions were True
elif not <condition1> and not <condition2> and not <condition3>:
# All three conditions were False
Of course, you could also use all and any:
if all((<condition1>, <condition2>, <condition3>)):
# All three conditions were True
elif not any((<condition1>, <condition2>, <condition3>)):
# All three conditions were False
Maybe this would be useful for you:
x = 1
y = 2
z = 3
my_function(x if x > z else y) # function called with y
x = 4
my_function(x if x > z else y) # function called with x
It can of course be combined with all() and any() as described by others.

See if all items in a list = certain string

How would I find if I have a list of a given string, 'hello':
x = ['hello', 'hello', 'hello']
# evaluates to True
x = ['hello', '1']
# evaluates to False
Use the all() function to test if a condition holds True for all elements:
all(el == 'hello' for el in x)
The all() function takes an iterable (something that produces results one by one) and will only return True itself if all those elements are true. The moment it finds anything that is false, it'll return False and not look further.
Here the iterable is a generator expression, one that executes an equality test for each element in the input sequence. The fact that all() stops iterating early if a false value is encountered makes this test very efficient if the test in the contained generator expression is False for any element early on.
Note that if x is empty, then all() returns True as well as it won't find any elements that are false in an empty sequence. You could test for the sequence being non-empty first:
if x and all(el == 'hello' for el in x):
to work around that.
This ought to work:
# First check to make sure 'x' isn't empty, then use the 'all' built-in
if x and all(y=='hello' for y in x):
Nice thing about the all built-in is that it stops on the first item it finds that doesn't meet the condition. This means it is quite efficient with large lists.
Also, if all of the items in the list are strings, then you can use the lower method of a string to match things like `'HellO', 'hELLO', etc.
if x and all(y.lower()=='hello' for y in x):
Yet another way to do what you want (all is the most idiomatic way to do that, as all other answers note), useful in case if you need to check more than once:
s = set(l)
cond = (len(s) == 1) and (item in s)
It helps to avoid O(n) traversal every time you want to check the condition.
Using filter and len is easy.
x = ['hello', 'hello', 'hello']
s = 'hello'
print len(filter(lambda i:i==s, x))==len(x)
Youn can do that using set:
set(x) == {'hello'}

How to do "if-for" statement in python?

With python, I would like to run a test over an entire list, and, if all the statements are true for each item in the list, take a certain action.
Pseudo-code: If "test involving x" is true for every x in "list", then do "this".
It seems like there should be a simple way to do this.
What syntax should I use in python?
Use all(). It takes an iterable as an argument and return True if all entries evaluate to True. Example:
if all((3, True, "abc")):
print "Yes!"
You will probably need some kind of generator expression, like
if all(x > 3 for x in lst):
do_stuff()
>>> x = [True, False, True, False]
>>> all(x)
False
all() returns True if all the elements in the list are True
Similarly, any() will return True if any element is true.
Example (test all elements are greater than 0)
if all(x > 0 for x in list_of_xs):
do_something()
Above originally used a list comprehension (if all([x > 0 for x in list_of_xs]): ) which as pointed out by delnan (Thanks) a generator expression would be faster as the generator expression terminates at the first False, while this expression applies the comparison to all elements of the list.
However, be careful with generator expression like:
all(x > 0 for x in list_of_xs)
If you are using pylab (launch ipython as 'ipython -pylab'), the all function is replaced with numpy.all which doesn't process generator expressions properly.
all([x>0 for x in [3,-1,5]]) ## False
numpy.all([x>0 for x in [3,-1,5]]) ## False
all(x>0 for x in [3,-1,5]) ## False
numpy.all(x>0 for x in [3,-1,5]) ## True
I believe you want the all() method:
$ python
>>> help(all)
Help on built-in function all in module __builtin__:
all(...)
all(iterable) -> bool
Return True if bool(x) is True for all values x in the iterable.
if reduce(lambda x, y: x and involve(y), yourlist, True):
certain_action()
involve is the action you want to involve for each element in the list, yourlist is your original list, certain_action is the action you want to perform if all the statements are true.
all() alone doesn't work well if you need an extra map() phase.
see below:
all((x==0 for x in xrange(1000))
and:
all([x==0 for x in xrange(1000)])
the 2nd example will perform 1000 compare even the 2nd compare render the whole result false.

Categories