I have a list of lists in Python. As illustrated below, I want to check if one of the sublists contains an item. The following attempt fails. Does anyone know of a simple way -- without me writing my own for loop?
>>> a = [[1,2],[3,4],[5,6],7,8,9]
>>> 2 in a
I was hoping for True but the return was False
>>> a = [[1,2],[3,4],[5,6],7,8,9]
>>> any(2 in i for i in a)
True
For a list that contains some lists and some integers, you need to test whether the element i is a list before testing whether the search target is in i.
>>> any(2 in i for i in a if isinstance(i, list))
True
>>> any(8 in i for i in a if isinstance(i, list))
False
If you don't check whether i is a list, then you'll get an error like below. The accepted answer is wrong, because it gives this error.
>>> any(8 in i for i in a)
Traceback (most recent call last):
File "<pyshell#3>", line 1, in <module>
any(8 in i for i in a)
File "<pyshell#3>", line 1, in <genexpr>
any(8 in i for i in a)
TypeError: argument of type 'int' is not iterable
I think this type of situation is where we can take some inspiration from functional programming by delegating the evaluation of the boolean expression to its own function. This way, if you need to change the behaviour of your bool condition, you only need to change that function definition!
Let's say you want to check sublists AND also int that happen to be in the top level. We can define a function that returns a boolean when performing a comparison on a single list element:
def elem(a, b):
'''
Defines if an object b matches a.
'''
return (isinstance(b, int) and a == b) or (isinstance(b, list) and a in b)
Note here that this function says nothing about our list - the argument b in our usage is just a single element within the list, but we could just as easily call it just to compare two values. Now we have the following:
>>> a = [[1,2],[3,4],[5,6],7,8,9]
>>> any(elem(2, i) for i in a)
True
>>> any(elem(8, i) for i in a)
True
>>> any(elem(10, i) for i in a)
False
Bingo! Another benefit of this type of definition is that it allows you to partially apply functions, and gives you the ability to assign names to searches for only one type of number:
from functools import partial
>>> contains2 = partial(elem, 2)
>>> any(map(contains2, a))
True
>>> b = [[1],[3,4],[5,6],7,8,9]]
>>> any(map(contains2, b))
False
In my opinion, this makes for more readable code at the cost of a bit of boilerplate and the need to know what map does - since you can make your variable names sensical rather than a jungle of temporary list comprehension variables. I don't particularly care if the functional approach is less Pythonic - Python is a multiparadigm language and I think it looks better this way, plain and simple. But that's personal choice - it's up to you.
Now let's say that our situation has changed and we now want to check only the sublists - it's not enough for an occurrence in a top level. That's okay because now all we need to change is our definition of elem. Let's see:
def elem(a, b):
return isinstance(b, list) and a in b
We've just removed the possibility of a match in the case that b is a top level int! If we run this now:
>>> a = [[1,2],[3,4],[5,6],7,8,9,"a",["b","c"]]
>>> any(elem(2, i) for i in a)
True
>>> any(elem(8, i) for i in a)
False
I'll illustrate one final example that really drives home how powerful this type of definition is. Suppose we have a list of arbitrarily deeply nested lists of integers. How do we check if an integer is in any of the levels?
We can take a recursive approach - and it doesn't take much modification at all:
def elem(a, b):
return (isinstance(b, int) and a == b) or \
(isinstance(b, list) and any(map(partial(elem, a), b)))
Because we've used this recursive definition that is defined to act on a single element, all the previous lines of code used still work:
>>> d = [1, [2, [3, [4, 5]]]]
>>> any(elem(1, i) for i in d)
True
>>> any(elem(4, i) for i in d)
True
>>> any(elem(10, i) for i in d)
False
>>> any(map(contains2, d))
True
Of course, given that this function is now recursive, we can really just call it directly:
>>> elem(4, d)
True
But the point remains that this modular approach has allowed us to alter the functionality by only changing the definition of elem without touching our main script, which means less TypeErrors and quicker refactoring.
I don't think there's any way of doing the test without a loop of some kind.
Here's a function that uses a straightforward for loop to explicitly check for an object within a sublist:
def sublist_contains(lst, obj):
for item in lst:
try:
if obj in item:
return True
except TypeError:
pass
return False
Of course, that doesn't test if the object is in the top level list, nor will it work if there is more than one level of nesting. Here's a more general solution using recursion, which puts the loop in a generator expression that's passed to the built-in function any:
def nested_contains(lst, obj):
return any(item == obj or
isinstance(item, list) and nested_contains(item, obj)
for item in lst)
Simple way to do this is:
a = [[1,2],[3,4],[5,6],7,8,9]
result = [2 in i for i in a]
True in result --> True
Related
I have a float number x and a list range list_ = [[a, b], [c,d], [e,f]]
How can check if the number x is in the list. It means the function will return True in case of
a<=x <=b
or
c<=x <=d
or
e<=x <=f
Otherwise, the function will return False. Could you help me to write a Python code for the function
function (x, list_)--> True/False
Clean solution:
def function(x, list_):
return any([l[0] < x < l[1] for l in list_])
Optimized solution:
def function(x, list_):
for l in list_:
if l[0] < x < l[1]:
return True
return False
The idiomatic solution would be this:
def f(x: int, ls: List[Tuple[float, float]]) -> bool:
return any(a <= x <=b for (a, b) in ls)
Take specific note of the following:
Naming a function function is a super poor idea.
It is abnormal and therefore a poor idea to name a variable list_ just to avoid overriding a keyword.
Using the form any ensures that you quickly quit when you find a valid solution.
You can quickly destructure your tuple (or list, if you happen to pass a list) using the for (a, b) in ls clause.
This solution is as quick as if you use a for clause, but all of that is premature optimization anyway.
Using an explicit destructing ensures you have two and only two elements for your sublist.
It was requested that I check certain inputs:
>>> f(10.1, [[8.1, 12.1], [110, 120]])
True
Seems to work!
If you're running into NameError, the issue is simply one of the importation of types. You can either define f like so:
def f(x, ls):
... // As you would otherwise
Or import the required types to make the type-hinting work properly:
from typing import List, Tuple
def f(x: int, ls: List[Tuple[float, float]]) -> bool:
... // As you would otherwise
This has little to do with the original question or solution - it's just standard for type hinting in python.
def function(x,list__):
for [a,b] in list_data:
if a<=x<=b:
return True
return False
You can simply iterate through the list and find whether it's in range or not.
I'm generating the variable and the list randomly and calling a function that iterates and checks whether the variable lies within the range of any of the members of the list.
import numpy as np
def find_if_in_range(list_, var) -> bool:
for i in list_:
if i[0] <= var <= i[-1]:
return True
return False
var = np.random.randint(10)
list_ = np.random.randint(10, size=(3,2), dtype=np.uint8)
print(f"var: {var}")
print(f"list: {list_}")
res = find_if_in_range(list_, var)
print(res)
Output:
var: 0
list: [[0 6]
[2 7]
[7 9]]
True
Hope this helps.
Cheers.
I'm writing an object serializer but am having issues where the class patterns are not matching the expected cases:
def dump_obj(x):
match(x):
case list():
emit('L')
dump_obj(len(x))
for elem in x:
dump_obj(elem)
case Iterable():
emit('I')
dump_obj((type(x), list(x)))
case tuple():
emit('T')
dump_obj(list(x))
case str():
emit('S')
dump_obj(len(x))
emit(x)
case int():
emit('D')
emit(str(x))
case _:
raise TypeError(f'Unknown obj {x!r}')
When I call dump_obj() with a tuple, it giving an infinite recursion on the I-case for iterables rather than matching the T-case for tuples.
When I call dump_obj() with a list subclass, it is matching the L-case for lists instead of the intended I-case for iterables.
First problem: Ordering
The cases are not independent of one another. They are tested from the top-down (like a long if/elif chain) and the first to match wins.
In the example, the specific match tests like like list, tuple, and str need to come before more general matches like Iterable. Otherwise with the current code, a tuple input like (10, 20, 30) will match the I-case instead of the intended T-case.
Second problem: Specificity
A class pattern performs an isinstance() check which would match both a type and subclasses of the type. To restrict the case to an exact match, use a type guard:
case list() if type(x) == list:
...
Putting it all together
With both solutions applied, here is the new code:
def dump_obj(x):
match(x):
case list() if type(x) == list: # <-- Added guard
emit('L')
dump_obj(len(x))
for elem in x:
dump_obj(elem)
case tuple() if type(x) == tuple: # <-- Added guard
emit('T')
dump_obj(list(x))
case str() if type(x) == str: # <-- Added guard
emit('S')
dump_obj(len(x))
emit(x)
case Iterable(): # <-- Move after list, tuple, str
emit('I')
dump_obj((type(x).__name__, list(x)))
case int():
emit('D')
emit(str(x))
case _:
raise TypeError(f'Unknown obj {x!r}')
Sample runs
Here we show that the two problematic cases work as expected.
>>> dump_obj((10, 20)) # Tuple of integers
T
L
D
2
D
10
D
20
>>> class List(list):
... pass
...
>>> dump_obj(List((30, 40))) # List subclass
I
T
L
D
2
S
D
4
List
L
D
2
D
30
D
40
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
I'm trying to return 1 instead of None when I pass an empty list through reduce(mul, a). My code:
from operator import mul
def product_list(a):
for b in a:
b = reduce(mul, a)
if b == None:
return 1
return b
print product_list([])
No matter where I place the if statement to catch for a blank list, I still receive None as output. I am still learning basics, but this makes no sense to me. I've even tried
from operator import mul
def product_list(a):
if a == None:
return 1
else:
for b in a:
b = reduce(mul, a)
if b == None or a == None:
return 1
return b
print product_list([])
just to see if it would catch the None and return 1. Does reduce() not act the way I think that it does, or is there an obvious mistake in my code that prohibits returning 1 and forces a return of None?
When a is an empty list, your function doesn't return anything, and the default return value is None.
Test for the empty list at the top:
if not a:
return 1
In your second function you only test for if a == None, but an empty list [] is never equal to None. Note that the idiomatic way to test for None is using the is object identity test instead:
if a is None:
By testing for not a instead, you catch both the case where a is an empty list and a being None.
Your code otherwise makes little sense. You loop over a but return and exit the function in the first iteration:
for b in a:
b = reduce(mul, a)
if b == None:
return 1
return b # exit the function here, having only looked at the first element in `a`.
However, I had to fix the indentation in your post and may have misunderstood the indentation of those return statements, in which case you would get a NameError instead when passing in an empty list.
You can pass a third value to reduce, which is used as a starter value.
In [6]: reduce(mul, [], 1)
Out[6]: 1
This is the best way to deal with an empty list. The case None should really be dealt with elsewhere, because it's a different kind of error: it's nothing wrong with the semantics of the program, it's because someone else has given you bad data. You should catch that explicitly, as e.g.
if not isinstance(..., collections.Iterable):
# do something
Of course, reduce will raise an error if you pass it something not iterable, and that may suffice for you.
Note that you're not passing an empty list to reduce as you say. Try it:
>>> reduce(operator.mul, [])
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: reduce() of empty sequence with no initial value
I think that perhaps you don't understand the function reduce. We can't hold it against you though -- it's not used much in python code.
Perhaps you wanted to define a function like this:
from operator import mul
def product_list(a):
try:
return reduce(mul,a)
except TypeError:
return 1
Now you can try it:
print product_list([1,2,3,4]) #24
print product_list([]) #1
if a is None or len(a) == 0:
return 1
Check the empty list condition as above.