Is there a way to write an If (or equivalent) statement that can have many arguments, and if any of those satisfy the logic, use that variable?
For instance
if len(x) == 1 or len(y) == 1 or len(z) == 1 or ... len(zz) == 1:
# do something with the variable that met the condition
So say only z has length 1, could I write above idea/formula in a way that takes the first True answer and use that?
So something like
x = "123"
y = "234"
z = "2"
xx = "1234"
yy = "12345"
if len(x) == 1 or len(y) == 1 or len(z) == 1 or len(xx) == 1 or len(yy) == 1:
#do something with the variable that satisfies the condition, so `z` in this case.
Does that make any sense? The variables' lengths could change any time, so I'd like to be able to say "If any of the conditions are met, use the variable that met the condition"...?
In the above, I don't know beforehand that zwill be the only one to meet the criteria, so my Then statement can't be z = "new value" or whatever I want
to do with it.
Edit: Sorry, per comments I know checking for len on integers isn't okay. This is solely for illustration purposes and it was the first thing I thought of to "test". Sorry if the len bit is confusing. I'm mainly just trying to see if I can use If statements (or related ones) where I don't know which of my many variables will meet a condition. (I'm still new regarding python, so my sincere apologies for my lack of semantics or proper terms). I'd like to avoid elif if at all possible just because it can get stringy. (But if that's the most pythonic way, then so be it!)
While #pault 's answer addresses your question, I think it isn't super readable.
If you have a couple of variables only, pythons mantra dictate a straightforward, explicit way:
if len(x) == 1:
f(x)
elif len(y) == 1:
f(y)
elif len(z) == 1:
f(z)
Otherwise, if you have a list, a for loop is readable and efficient:
for l in ls:
if len(l) == 1:
f(l)
break
You could use next here to pick the first item out of a list of options that meets your criteria:
value = next((item for item in [x, y, z] if len(item)==1), None)
if value is not None:
...
The second argument to next() is the default value if no values meet your criteria.
What you describe has a general implementation called first_true in the itertools recipes.
def first_true(iterable, default=False, pred=None):
"""Returns the first true value in the iterable.
If no true value is found, returns *default*
If *pred* is not None, returns the first item
for which pred(item) is true.
"""
# first_true([a,b,c], x) --> a or b or c or x
# first_true([a,b], x, f) --> a if f(a) else b if f(b) else x
return next(filter(pred, iterable), default)
Example
value = first_true([x, y, z], pred=lambda x: len(x) == 1)
if value:
...
A small list comprehension would suffice:
passed = [i for i in (x, y, z, xx, yy) if len(i) == 1]
if passed:
# ... use the ones that passed, or 'passed[0]' for the first item
Related
I am building an evaluator and often encounters this code pattern. Is there a simpler (shorter, more Pythonic, etc) way to write this? It should either return None if the list of operands is empty, the first operand if there is only one to process, and actually create an Add node by calling a function otherwise.
# l contains a list of operands to process
if not l: ans = None
elif len(l) == 1: ans = l[0]
else: ans = createAddNode(*l) # returns Add(a, b, c, ...)
return ans
I find myself repeating this code pattern for various operations like subtract, multiply, divide, etc
Since in python you do not have to specify the return type of a function, you can omit the first line.
if l:
ans = l[0] if len(l) == 1 else createAddNode(*l)
return ans
It's quite hard to answer this without context but I will try and give some suggestions
def test(l):
# l contains a list of operands to process
if not l:
ans = None
elif len(l) == 1:
ans = l[0]
else:
ans = createAddNode(*l) # returns Add(a, b, c, ...)
return ans
at the very least you should have these if statements on separate lines for readability.
if not l:
ans = None
This statement is rather redundant as you are already evaluating whatever is stored in the collection "l" to empty
elif len(l) == 1:
ans = l[0]
this suggestion depends on what "createAddNode" does but once again this seems rather redundant. I would find a way to evaluate this expression inside "createAddNode".
def test(l):
# l contains a list of operands to process
if l:
return createAddNode(*l) # returns Add(a, b, c, ...)
this would be my final function assuming you refactor createAddNode to handle the base case where length is one. This will return None if l is empty
Just as a side note I don't see a point in unpacking a variable amount of arguments in your "createAddNode" function. Odds are you can probably just do this with a for loop, but this obviously depends on what you are trying to unpack.
I am trying to write a code for below pseudocode
for all element in list do
match and condition
if all match
return True
for example, List A=[1,2,3,4,5],B=10
What I want is like
def match():
for i in range(len(A)):
if B%A[0]==0 and B%A[1]==0 and B%A[2]==0 and B%A[3]==0 and B%A[4]==0: #Generate all these
#and condition one by one
#automatically in this function
return True
How can I do?
NOTE:I am asking about write code match and condition with a loop, not write a remainder
Try this one:
result = all( [(B%a==0) for a in A] )
You can use a pythonic one liner
result = all(B % x == 0 for x in A)
Or maybe in a slightly more familiar syntax
res = True
for x in A:
if B % x != 0:
res = False
break
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
I have made the function, but I need to make a guess so it will run through the function and check if it fits, if not, start over again with new numbers.
If I find a set that works, the loop should break, the problem is that I am new to python and math programming.
def checkStuff(X):
ok = True
#i.
if(min(X) <= 0):
ok = False
#ii.A
A = set()
for x in X:
A.add(x % 2)
#ii.B
B = set()
for y in X:
B.add(y**2)
#ii.C
C = set()
for z in X & B:
C.add(z**0.5)
#ii.D
D = set()
for w in C:
D.add(w**2)
#iii.
if(len(X)<=0):
ok = False
#iv.
if(len(X) not in X):
ok = False
#v.
if len(A) in X:
ok = False
#vi.
if sum(X) not in B:
ok = False
#vii.
if sum(X&B) in B:
ok = False
#viii.
if sum(C.union(D)) not in X:
ok = False
return ok
without giving you the exact code, try looking at the while loop and the random function
Your function can be simplified and optimized, returning as soon as possible, avoiding further computations... for compactness I used set comprehensions instead of your loops
def checkStuff(X):
if(min(X) <= 0): return False
if(len(X)<=0): return False
if(len(X) not in X): return False
A = {x % 2 for x in X}
if len(A) in X: return False
B = {x**2 for x in X}
if sum(X) not in B: return False
if sum(X&B) in B: return False
C = {xb**0.5 for xb in X&B}
D = {c**2 for c in C}
if sum(C.union(D)) not in X: return False
return True
Assuming that you have a function that returns a list of trial sets or, possibly better, yields a new trial set for each loop, and that you want to use ONLY the first X that matches your conditions, then you can write your stuff like this
for X in generate_trial_sets():
if checkStuff(X):
do_stuff(X)
break
else:
print("No X was generated matching the criteria")
...
Note that the else clause is aligned correctly, because Python has a for ... else .. control flow construct.
Blind Attempt at a generate_trial_sets Function
Given that each X is a set of numbers (integers? reals? complex numbers? who knows? you, but you didn't care to tell...) and that we don't know how many numbers you want in the set, and also that you want to stop the iteration somehow, I'd write
def generate_trial_sets(nmin=1, nmax=5,
xmin=0.0, xmax=10.0, iterations=10):
from random import randint
for _ in range(iterations):
n = randint(nmin,nmax+1)
x = {n}
for i in range(1,n):
x.add((xmax-xmin)*random()+xmin)
yield x
When you call it like
for X in generate_trial_sets():
without modifying the default args, you get back 10 sets of length comprised between 1 and 5, with real values comprised between 0 and 10 (one of the values is equal to the length, so one of your tests is automatically fulfilled).
To use different parameters, specify them at the invocation:
for X in generate_trial_sets(nmin=6,nmax=6,xmax=100.0,iterations=200):
This is not a solution of your problem but if you understand the logic you'll get started in the right direction or, at least, I hope so...
Basic stuff I know...;-P But what is the best way to check if a function returns some values?
def hillupillu():
a= None
b="lillestalle"
return a,b
if i and j in hillupillu(): #how can i check if i or j are empty? this is not doing it of course;-P
print i,j
If you meant that you can't predict the number of return values of some function, then
i, j = hillupillu()
will raise a ValueError if the function doesn't return exactly two values. You can catch that with the usual try construct:
try:
i, j = hillupillu()
except ValueError:
print("Hey, I was expecting two values!")
This follows the common Python idiom of "asking for forgiveness, not permission". If hillupillu might raise a ValueError itself, you'll want to do an explicit check:
r = hillupillu()
if len(r) != 2: # maybe check whether it's a tuple as well with isinstance(r, tuple)
print("Hey, I was expecting two values!")
i, j = r
If you meant that you want to check for None in the returned values, then check for None in (i, j) in an if-clause.
Functions in Python always return a single value. In particular they can return a tuple.
If you don't know how many values in a tuple you could check its length:
tuple_ = hillupillu()
i = tuple_[0] if tuple_ else None
j = tuple_[1] if len(tuple_) > 1 else None
After receiving the values from the function:
i, j = hillupillu()
You can check whether a value is None with the is operator:
if i is None: ...
You can also just test the value's truth value:
if i: ...
if(i == "" or j == ""):
//execute code
something like that should wordk, but if your giving it a None value you would do this
if(i == None or j == None):
//execute code
hope that helps
You can check whether the return value of the function is a tuple:
r_value = foo(False)
x, y = None, None
if type(r_value) == tuple:
x, y = r_value
else:
x = r_value
print(x, y)
This example is suited for a case where the function is known to return either exactly one tuple of length 2 (for example by doing return a, b), or one single value. It could be extended to handle other cases where the function can return tuples of other lengths.
I don't believe #Fred Foo's accepted answer is correct for a few reasons:
It will happily unpack other iterables that can be unpacked into two values, such as a list or string of lengths 2. This does not correspond to a return from a function that returned multiple values.
The thrown exception can be TypeError, not a ValueError.
The variables that store the return value are scoped to the try block, and so we can only deal with them inside that block.
It doesn't show how to handle the case where there is a single returned value.