Related
Sorry for for the potentially silly question. But this seems to be a stumping problem I just can't find the answer to.
Say I have the following mixed nested list in python:
a = [((1,1),(0,0)), (3,4)]
I'd like to check if the following tuples b, c and d appear in a:
b = (1,1)
c = (0,0)
d = (3,4)
print(b in a) # <- False ?
print(c in a) # <- False ?
print(d in a) # <- True
I'd like to replace the code in each print statement in such away that the search finds the tuple in the list and as such returns True
Any help at all would be much appreciated. Apologies if this question has already been asked before.
We need a recursive function that takes a list or tuple and an element to find.
Each function should check whether the element is in the current iterable using the in operator. If it is in then return True, otherwise check if it is in any of the lower dimensions by recursively calling itself with each of the lower iterables and return if any of those succeeded (this can be done with a for-loop, but we may as well use the any() function).
So a one liner would be roughly:
def inc(it, e):
return True if e in it else any(inc(iit, e) for iit in it if type(iit) in (list, tuple))
And it works as intended:
>>> inc(a, (1,1))
True
>>> inc(a, (0,0))
True
>>> inc(a, (3,4))
True
The list has two elements, a tuple which contains other tuples, and a tuple of ints. If you want to check the nested structures, you are going to have to do that yourself. A recursive solution (this one assumes the nested containers can only be either tuple's or lists) would be one option if nesting can be arbitrarily deep:
>>> a = [((1,1),(0,0)), (3,4)]
>>> def is_in(x, nested):
... result = False
... if not isinstance(nested, (tuple, list)):
... return result
... for item in nested:
... if x == item:
... result = True
... else:
... result = result or is_in(x, item)
... if result:
... return True
... return result
...
>>> is_in((1,1), a)
True
>>> is_in((0,0), a)
True
>>> is_in((3,4), a)
True
>>> is_in((8, 8), a)
False
>
This should stop traversing once the first match is found.
Note, if recursion isn't your thing, you can replace the call stack with your own stack!
def is_in_iterative(x, nested):
stack = [nested]
while stack:
item = stack.pop()
print(item)
if item == x:
return True
elif isinstance(item, (list, tuple)):
stack.extend(item)
return False
However, note that this will check in the reverse order...
i tried to solve your problem by recursive function method and global variable defining , i wish this solution can give you idea:
a = [((1,1),(0,0)), (3,4)]
global bb
bb=False
def checker(tuple1, tuple2):
b=str(type(('a','b')))
for i in range(len(tuple1)):
if(str(type(tuple1[i]))!=b):
if (tuple1==tuple2):
global bb
bb=True
else:
checker(tuple1[i],tuple2)
checker(a,(1,1))
print(bb)
#-->True
bb=False
checker(a,(3,4))
print(bb)
#-->True
bb=False
checker(a,(0,0))
print(bb)
#--->True
bb=False
checker(a,(10,1))
print(bb)
#--->False
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
Is there any prettier way to write this if-statement:
if not (self.is_legal(l) or self.is_legal(u) or self.is_legal(r) or self.is_legal(d)):
I've tried this, but it didn't work.
if not self.is_legal(l or r or d or u):
Or maybe the first one is the prettiest?
You can use any and a generator expression:
if not any(self.is_legal(x) for x in (l, u, r, d)):
Or, if you prefer all instead of any:
if all(not self.is_legal(x) for x in (l, u, r, d)):
The first solution seems to read a little better though.
As for why your attempted solution did not work, the or operator in Python does not behave as you think it does. From the docs:
The expression x or y first evaluates x; if x is true, its value
is returned; otherwise, y is evaluated and the resulting value is
returned.
So, self.is_legal(l or r or d or u) was only passing the first truthy value to the self.is_legal method, not all of them.
An empty list in Python is false.
You can produce an empty list with a comprehension and a conditional like so:
>>> def is_legal(x):
... return x>5
...
>>> bool([x for x in (1,2,3,4) if is_legal(x)])
False
>>> bool([x for x in (1,2,3,4,6) if is_legal(x)])
True
You can use a tuple or set:
if False in (self.is_legal(l), self.is_legal(u), self.is_legal(r), self.is_legal(d)):
if {False} <= {self.is_legal(l), self.is_legal(u), self.is_legal(r)}:
Extending this idea a bit further:
if {False} <= {self.is_legal(var) for var in (l, u, r, d)}:
Or using the fact that an empty list or set or whatever is false:
if [var for var in (l, u, r, d) if self.is_legal(var) is False]:
I guess it all depends on what you consider to be "pretty".
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'}
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)