如何检查列表是否为空

时间:2018-10-26 02:37:38

标签: python python-3.x

我对空列表的定义是:

a = []
a = [[], []]
a = [[], [], [[], []]]

通用方法不适用,因为最后两个列表的长度不为0,在if条件下,它们将被视为True。

if a:
    print(True)    # True
#-------------------------
print(len(a) != 0) # True

有什么好的检查方法吗?

6 个答案:

答案 0 :(得分:2)

Kinda很傻,但可能是不错的解决方案:

if str(a).strip('[], '):

或者list可能包含自身,并且应该算作空:

if str(a).strip('[], .'):

依靠这样一个事实,list仅用方括号,空格和逗号来表示,但是它们包含的任何内容(没有故意引起病的repr)都具有一些涉及的其他角色。包含自身的list在递归时使用...,因此剥离处理它们。因此,我们strip仅出现在空白list和空白list的空白listlist中的唯一字符,如果还剩下任何内容,则表示存在非{{1 }}在那里。

答案 1 :(得分:1)

您可以使用一个功能来递归检查子列表中的项目:

def is_empty(l):
    return all(is_empty(i) if isinstance(i, list) else False for i in l)

这样:

print(is_empty([[], [], [[], []]]))
print(is_empty([[], [], [[], [1]]]))

输出:

True
False

如果要处理包含循环引用的列表,则可以使用seen集来跟踪该函数已看到的列表引用,并在看到它们时跳过它们:

def is_empty(l, seen=None):
    if seen is None:
        seen = set()
    return all(seen.add(id(i)) or is_empty(i, seen) if isinstance(i, list) else False for i in l if id(i) not in seen)

这样:

a = []
a.append(a)
print(is_empty(a))
a = [1]
a.append(a)
print(is_empty(a))

输出:

True
False

答案 2 :(得分:0)

要检查每个项目,有一种简单但有用的方法。

In [65]: a = [[], [], [[], [1]]]
In [66]: mark = []
In [67]: def recursive_check(lst, mark):
    ...:     for i in lst:
    ...:         if isinstance(i, list):
    ...:             recursive_check(i, mark)
    ...:         else:
    ...:             mark.append(i)
    ...:     return mark

然后,您可以在调用recursive_check

之后检查全局标记值
recursive_check(a, mark)

,您可以轻松检查标记值,例如:

if mark:
    pass

每次通话后,如果您在terminal上运行,请不要忘记将mark重置为空。

mark=[]

要使其易于使用,可以添加另一个函数对其进行包装。

In [77]: def test(lst):
    ...:     mark = []
    ...:     return len(recursive_check(lst, mark)) != 0
    ...: 

In [78]: a
Out[78]: [[], [], [[], [1]]]

In [79]: test(a)
Out[79]: True

In [80]: cc
Out[80]: [[], [], [[], []]]

In [81]: test(cc)
Out[81]: False

答案 3 :(得分:0)

我认为您可能需要递归。试试这个:

  def is_empty(arr, seen=None):
      # Infinite loops detection
      if seen is None:
          seen = set()
      if id(arr) in seen:
          arr.remove(arr)
      seen.add(id(arr))

      if isinstance(arr, list):
          if arr:
              return all(is_empty(b, seen) for b in arr)
          else:
              return True
      else:
          return False

基本上,任何不是列表的内容都意味着您的列表不为空。如果找到非空列表,它将开始查找其中的每个元素。如果除了列表中还有任何元素,它将返回False

经过编辑以避免无限循环(感谢@MadPhysicist!)

答案 4 :(得分:0)

您需要的解决方案不仅要递归,还要防止无限递归。这是一种可能性:

def has_non_list(x):
    """ Assumes x is a list """
    seen = set()  # stash IDs since lists aren't hashable
    def check(x):
        if id(x) in seen:
            return False
        seen.add(id(x))
        for i in x:
            if not isinstance(i, list) or check(i):
                 return True
        return False
    return check(x)

使此序列适用于任何序列应该很容易。

答案 5 :(得分:0)

更可组合/可重用的答案是使生成器函数展平嵌套的list(或为提高可重用性,使用任意可迭代对象),从而使结果迭代变得微不足道;如果它产生任何东西,则它是非空的(并且您可以立即停止迭代,以节省list中潜在的list s上的工作),否则为空:

def flatten(it, skip_same_list=True):
    '''Returns a generator of all non-lists in possibly nested list

    If skip_same_list is False, this will produce infinite output if a list is
    nested inside itself'''
    stack = [it]
    seen = set()
    while stack:
        item = stack.pop()
        if isinstance(item, list):
            if skip_same_list:
                if id(item) in seen:
                    continue  # Ignores same list if seen again
                seen.add(id(item))
            stack.extend(reversed(item))
        else:
            yield item

有了这些,解决问题就变得微不足道了:

def my_is_empty(it, *, _sentinel=object()):
    # Two arg next returns the first item or _sentinel if no items yielded
    return next(flatten(it), _sentinel) is _sentinel

# Alternative without sentinel object:
def my_is_empty(it):
    try:
        next(flatten(it))
    except StopIteration:
        return True
    return False

如果您想要任意嵌套的可迭代对象以提高适用性,而不仅仅是list,则flatten的代码会变得更加复杂,而my_is_empty则保持不变。

my other answer相比,这显然是更复杂的代码,但它也是非启发式的(因此,具有真正奇怪的repr的类型不能欺骗它),可重复用于其他目的,并且当大多数输入为非空时,尤其是输入较大时,速度会更快(因为它会在发现非空状态确认后立即停止处理,而不会浪费时间list上的其余时间)。