检查一个项目是否在一个嵌套列表中。

23

在一个简单的列表中,以下检查是微不足道的:

x = [1, 2, 3]

2 in x  -> True

但如果它是一个列表的列表,例如:

x = [[1, 2, 3], [2, 3, 4]]

2 in x   -> False

如何解决以便返回True

8个回答

33

试试这个,使用内置的any函数。这是最惯用的解决方案,也很高效,因为any会短路并在找到第一个匹配项后停止:

x = [[1, 2, 3], [2, 3, 4]]
any(2 in sl for sl in x)
=> True

在这种情况下,SL是什么? - DenCowboy
只是一个变量名,它代表“子列表”。 - Óscar López
你的解决方案并不完全符合我的需求,但它提供了足够的信息让我解决了我的问题。我已经发布了解决方案。它打印出嵌套元素,这些元素不在另一个嵌套列表中。 - Michael Swartz
我能够在列表中嵌套字典时使用any()。谢谢 +1 - Felipe Alvarez

10

这里是一个递归版本,可以处理任意层次的嵌套。

def in_nested_list(my_list, item):
    """
    Determines if an item is in my_list, even if nested in a lower-level list.
    """
    if item in my_list:
        return True
    else:
        return any(in_nested_list(sublist, item) for sublist in my_list if isinstance(sublist, list))

这里有几个测试:

x = [1, 3, [1, 2, 3], [2, 3, 4], [3, 4, [], [2, 3, 'a']]]
print in_nested_list(x, 2)
print in_nested_list(x, 5)
print in_nested_list(x, 'a')
print in_nested_list(x, 'b')
print in_nested_list(x, [])
print in_nested_list(x, [1, 2])
print in_nested_list(x, [1, 2, 3])

True
False
True
False
True
False
True

5
你可以使用set.issubset()itertools.chain():
In [55]: x = [[1, 2, 3], [2, 3, 4]]

In [56]: {4}.issubset(chain.from_iterable(x))
Out[56]: True

In [57]: {10}.issubset(chain.from_iterable(x))
Out[57]: False

您可以高效地检查多个项目的成员资格:
In [70]: {2, 4}.issubset(chain.from_iterable(x))
Out[70]: True

In [71]: {2, 4, 10}.issubset(chain.from_iterable(x))
Out[71]: False

1
为什么不直接使用4 in chain.from_iterable(x),避免使用set进行单个元素测试?毕竟,in可以用于任意可迭代对象,并且可以很好地短路,而无需要求元素是可哈希的。无论如何,我还是点了赞(chain是一个好的解决方案)。 - ShadowRanger
@ShadowRanger 当然,如果它只是一个(几个)一次性操作,那么无需转换为集合。谢谢提醒。 - Mazdak

2
这会起作用:
for arr in x:
    if 2 in arr:
        print True
        break

我会推荐Oscar的答案,因为在这里any是正确的选项。

这不会起作用,除非元素恰好在最后一个子列表中...而且,如果在更早的情况下找到该元素,它应该短路。这就是为什么这里需要使用any,请参见我的答案。 - Óscar López
刚刚测试过了,即使它不在最后一个子列表中,它仍然可以正常工作。 - KVISH
不,它不会。使用 x = [[3,3], [4,4]] 进行测试,它将工作,即使它不应该这样做。 - Óscar López

1

TL;DR

x = [0, [1, 2, 3], [2, 3, [4, 5, [6], []], [7, 8]]]
def find_n(input_list, n):
    for el in input_list:
        if el == n or (isinstance(el, list) and find_n(el, n)):
            return True
    return False
print(find_n(x, 6))

请注意,有趣的是:

def find_n(input_list, n):
    return any([el == n or (isinstance(el, list) and find_n(el, n)) for el in input_list])
return (find_n(x, 6))

执行速度较慢超过50%。

原始回答:

如果您的深度大于2怎么办?以下是一种处理通用情况的方法:

x = [0, [1, 2, 3], [2, 3, [4, 5, [6], []], [7, 8]]]

def flatten(input_list):
    flat_list = []
    for sublist_or_el in input_list:
        if isinstance(sublist_or_el, list):
            for sublist_or_el2 in flatten(sublist_or_el):
                flat_list.append(sublist_or_el2)
        else:
            flat_list.append(sublist_or_el)
    return flat_list

print(6 in flatten(x))

虽然我不确定速度如何,但正如我所说,这是一种可能对某些人有用的方法!

编辑 - 更好(更快)的答案:

如果找到n,这将减少所需的时间(实际上,即使没有找到,时间也会减少一半...)通过提前返回。这比@Curt F.的答案稍微快一点,比假设最大深度为2的函数创建要慢一些(被接受的答案)。

x = [0, [1, 2, 3], [2, 3, [4, 5, [6], []], [7, 8]]]
def find_n(input_list, n):
    flat_list = []
    for sublist_or_el in input_list:
        if isinstance(sublist_or_el, list):
            if find_n(sublist_or_el, n) == True:
                return True
        elif sublist_or_el == n:
            return True
    return False
print(find_n(x, 6))

快速计时(非常hacky,抱歉,今天很忙!):
import time

x = [0, [1, 2, 3], [2, 3, [4, 5, [6], []], [7, 8]]]

def a():
    def flatten(input_list):
        flat_list = []
        for sublist_or_el in input_list:
            if isinstance(sublist_or_el, list):
                for sublist_or_el2 in flatten(sublist_or_el):
                    flat_list.append(sublist_or_el2)
            else:
                flat_list.append(sublist_or_el)
        return flat_list
    return (6 in flatten(x))

def b():
    def find_n(input_list, n):
        flat_list = []
        for sublist_or_el in input_list:
            if isinstance(sublist_or_el, list):
                if find_n(sublist_or_el, n) == True:
                    return True
            elif sublist_or_el == n:
                return True
        return False
    return (find_n(x, 6))


zz = 0
for i in range(100000):
    start_time = time.clock()
    res = a()
    zz += time.clock() - start_time
print(a())
print((zz)/100, "seconds")

zz = 0
for i in range(100000):
    start_time = time.clock()
    res = b()
    zz += time.clock() - start_time
print(b())
print((zz)/100, "seconds")

1

Óscar Lopez的回答非常好!我推荐使用它。

然而,你可以使用itertools来展开列表并对其进行eval操作,因此:

import itertools

x = [[1, 2, 3], [2, 3, 4]]
2 in itertools.chain.from_iterable(x)

Output: True

此外,您还可以通过理解手动执行此操作:
x = [[1, 2, 3], [2, 3, 4]]
2 in [item for sub_list in x for item in sub_list]

Output: True

这只是其他制作方法,祝你好运。

如果我的列表中有浮点数元素,我会得到TypeError:'numpy.float32'对象不可迭代 - Khaned
嗨@Khaned!这个错误“numpy.float32”似乎是您想要迭代浮点值而不是可迭代对象。因此,看起来您有一个numpy.float32列表...检查正在迭代什么 - Brian Ocampo
我有一个numpy.float32列表,如何迭代它? - Khaned
但是,你的numpy.float32列表是"[numpy.float32(a), numpy.float32(b),...]"吗?还是一个包含numpy.float32列表的列表"[[numpy.float32(a), numpy.float32(b),...], [numpy.float32(a), numpy.float32(b),...], ...]"?因为我的代码示例适用于第二种类型(一个包含项目列表的列表,此处为numpy.float)。 - Brian Ocampo

0

我的代码基于Óscar López的解决方案。他的解决方案并不完全符合我的需求,但它提供了足够的信息让我找出了问题所在。因此,如果您在一个列表中有嵌套元素,并且需要查看它们是否在另一个嵌套列表中,这个方法是可行的。

#!python2

lst1 = [['a', '1'], ['b', '2'], ['c', '3'], ['d', '4'], ['e', '5']]
lst2 = [['b', '2'], ['d', '4'], ['f', '6'], ['h', '8'], ['j', '10'], ['l', '12'], ['n', '14']]

# comparing by index 0, prints lst1 items that aren't in lst2
for i in lst1:
    if not any(i[0] in sublst for sublst in lst2):
        print i
'''
['a', '1']
['c', '3']
['e', '5']
'''

print

# comparing by index 0, prints lst2 items that aren't in lst1
for i in lst2:
    if not any(i[0] in sublst for sublst in lst1):
        print i
'''
['f', '6']
['h', '8']
['j', '10']
['l', '12']
['n', '14']
'''

0

尝试

 2 in [i for sublist in x  for i in sublist]

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接