我有一个Python的列表,其中包含多个子列表。如下所示,我想检查其中是否有一个子列表包含某个元素。以下尝试失败了。有没有简单的方法可以做到这一点 -- 而不是我自己写循环?
>>> a = [[1,2],[3,4],[5,6],7,8,9]
>>> 2 in a
我原本期望的是
True
,但实际返回的是False
。我有一个Python的列表,其中包含多个子列表。如下所示,我想检查其中是否有一个子列表包含某个元素。以下尝试失败了。有没有简单的方法可以做到这一点 -- 而不是我自己写循环?
>>> a = [[1,2],[3,4],[5,6],7,8,9]
>>> 2 in a
True
,但实际返回的是False
。>>> a = [[1,2],[3,4],[5,6],7,8,9]
>>> any(2 in i for i in a)
True
any(8 in i for i in a)
-> TypeError: argument of type 'int' is not iterable
- kaya3对于包含一些列表和一些整数的列表,您需要在测试搜索目标是否在i中之前先测试元素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
>>> 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
我认为这种情况可以从函数式编程中汲取灵感,通过将布尔表达式的评估委托给自己的函数。这样,如果您需要更改布尔条件的行为,只需更改该函数定义!
假设您想检查子列表并且还要检查顶级中出现的int
。我们可以定义一个函数,在单个列表元素上执行比较时返回布尔值:
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)
需要注意的是,这个函数并没有涉及到我们的列表 - 在我们的使用中,参数b
只是列表中的一个单独元素,但我们同样可以用它来比较两个值。现在我们有了以下结果:
>>> 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
太棒了!这种定义的另一个好处是它允许您部分应用函数,并使您能够为仅搜索一种类型的数字指定名称:
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
map
的用法 - 因为你可以使用有意义的变量名,而不是一堆临时列表推导式变量。我并不特别在意函数式方法是否符合Python风格 - Python是一种多范式语言,我认为这样看起来更好,简单明了。但这是个人选择 - 这取决于你自己。
现在假设我们的情况已经改变,我们现在只想检查子列表 - 在顶层出现不够。这没问题,因为现在我们需要改变的只是elem
的定义。让我们看一下:
def elem(a, b):
return isinstance(b, list) and a in b
我们刚刚删除了当 b
是顶级整数时匹配的可能性!现在如果运行这段代码:
>>> 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
def elem(a, b):
return (isinstance(b, int) and a == b) or \
(isinstance(b, list) and any(map(partial(elem, a), b)))
>>> 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
>>> elem(4, d)
True
但问题在于,这种模块化的方法使我们只需更改elem
的定义而不必触及主要脚本,从而可以改变功能,这意味着更少的类型错误和更快的重构。
我认为没有任何一种方法可以在不使用某种循环的情况下进行测试。
这里有一个函数,它使用直接的for
循环来明确地检查子列表中是否存在对象:
def sublist_contains(lst, obj):
for item in lst:
try:
if obj in item:
return True
except TypeError:
pass
return False
any
:def nested_contains(lst, obj):
return any(item == obj or
isinstance(item, list) and nested_contains(item, obj)
for item in lst)
简单的方法是:
a = [[1,2],[3,4],[5,6],7,8,9]
result = [2 in i for i in a]
True in result --> True
TypeError: argument of type 'int' is not iterable
- kaya3