从列表中移除任何空列表

24

我有一个列表:

i = [[1,2,3,[]],[],[],[],[4,5,[],7]]

我想要移除所有空列表:

[[1,2,3],[4,5,7]]

我该怎样做?

这是我的代码:

res = [ele for ele in i if ele != []]

2
打印([[j for j in ele if j] for ele in i if ele]) - Rakesh
1
成功了。谢谢!! - Avan Wansing
3
只有当你确定你的数组是二维的时候,这个方法才能起作用。如果有更多的维度或者在外层数组中存在非数组元素,那么这个方法将会失败。 - Muslimbek Abduganiev
1
@MuslimbekAbduganiev 请查看我的答案以获取更多维度数组。 - Muhammad Safwan
10个回答

15
使用递归函数从列表中删除空列表。
使用递归可以将空列表深度移除:
def remove_nested_list(listt):
    for index, value in enumerate(reversed(listt)):
        if isinstance(value, list) and value != []:
            remove_nested_list(value)
        elif isinstance(value, list) and len(value) == 0:
            listt.remove(value)


a = [[1, 2, 3, 0, []], [], [], [], [4, 5, [], 7]]
print(f"before-->{a}")
remove_nested_list(a)
print(f"after-->{a}")

输出:

before-->[[1, 2, 3, 0, []], [], [], [], [4, 5, [], 7]]
after-->[[1, 2, 3, 0], [4, 5, 7]]

3
如果输入的是零,则应输入“if not value:”。 - timgeb
5
如果您没有使用索引,为什么要枚举? - Teepeemm
4
另一个有趣的考虑是如何处理“[[]]”。看起来你的代码会删除内部的空列表,只留下“[]”。我不知道这是否是期望的结果。 - Teepeemm
1
@Teepeemm 不错的边缘情况。我想我们需要两个递归函数,一个用于检查是否为空嵌套列表,另一个用于删除它们。 - Ch3steR
另外,为什么你要以相反的顺序遍历列表? - Grajdeanu Alex
如果不按相反的顺序遍历,则由于listt.remove而操作实际数组位置。 - Muhammad Safwan

6

从任意嵌套列表中删除空列表,我们可以使用递归。 这里有一种简单的方法。我们需要遍历列表并检查元素是否为空列表。如果是,则不将其添加到最终列表中。如果它不是空列表,那么我们重复上述过程。

def remove_empty(lst):
    return (
        [remove_empty(i) for i in lst if i!=[]]
        if isinstance(lst, list)
        else lst
    )

输出:

i = [[1, 2, 3, []], [], [], [], [4, 5, [], 7]]
print(remove_empty(i))
# [[1, 2, 3], [4, 5, 7]]

# Example taken from iGian's answer 
ii = [[1, 2, 3, []], [], [], [], [4, 5, [], 7, [8, 9, [], [10, 11, []]]]] 
print(remove_empty(ii))
# [[1, 2, 3], [4, 5, 7, [8, 9, [10, 11]]]]

为了检查对象是否可迭代,我们使用 collections.abc.Iterable
from collections.abc import Iterable
all(
    isinstance(i, Iterable)
    for i in ([], tuple(), set(), dict(), range(10), (_ for _ in range(10)))
)
# True

现在,您可以使用isinstance(lst,Iterable)替换isinstance(lst, list)来过滤掉每个可迭代对象中的空列表,即[]

编辑:

@Teepeemm指出了一个所有答案都错过的精彩角落情况。

为了解决这个问题,我们需要两个递归函数,一个用于检查它是否为空嵌套列表,另一个用于删除空嵌套列表。

def empty(lst):
    if lst == []:
        return True
    elif isinstance(lst, list):
        return all(empty(i) for i in lst)
    else:
        return False

def remove_empty(lst):
    return (
        [remove_empty(i) for i in lst if not empty(i)]
        if isinstance(lst, list)
        else lst
    )

i = [[1, 2, 3, [[]]]] 
remove_empty(i)
# [[1, 2, 3]]
remove_nested_list(i) # Muhammad Safwan's answer
print(i) # [[1, 2, 3, []]]

ii = [[1, 2, 3, [[], [[[[], []]]]]]]
remove_empty(ii)
# [[1, 2, 3]]
remove_nested_list(ii) # Muhammad Safwan's answer
print(ii) # [[1, 2, 3, [[[[]]]]]]

4
我会使用一些不改变原始列表的方法。
第一个方法只是从列表中删除所有空列表,而不是嵌套的:
def remove_empty_lists(lst):
    return [ e for e in lst if not (isinstance(e, list) and len(e)==0) ]

第二种方法就是以递归的方式使用前者:
def deep_remove_empty_lists(lst):
    lst = remove_empty_lists(lst)
    return [ deep_remove_empty_lists(e) if isinstance(e, list) else e for e in lst ]

因此,在提交的案例中:
i = [[1,2,3,[]],[],[],[],[4,5,[],7]]
deep_remove_empty_lists(i)

#=> [[1, 2, 3], [4, 5, 7]]

或者在最深层嵌套的情况下:

ii = [[1,2,3,[]],[],[],[],[4,5,[],7,[8, 9, [], [10, 11, []]]]]
deep_remove_empty_lists(ii)

#=> [[1, 2, 3], [4, 5, 7, [8, 9, [10, 11]]]]

2

您可以使用列表推导式(实际上是嵌套的推导式):

i = [[1, 2, 3, []], [], [], [], [4, 5, [], 7]]

res = [[sub_item for sub_item in item if sub_item != []] for item in i if item != []]
print(res)

我们会两次检查空列表,一次是针对 i 中的容器列表,使用 if item != [],另一次是针对这些容器中的单个元素,使用 if sub_item != []


1
更符合 Python 风格的写法是 if item 而不是 if item != []。但这假设了 item 总是一个可能为空的列表,而不是其他可能为 Falsey 的值,比如 0 或 None。 - Teepeemm
1
@Teepeemm 没错。 - S.B

2

如果嵌套始终只有两层,就像你的问题一样,一种简洁的方法是:

>>> not_empty_list = lambda value: value != []

## Above is equivalent to:
#  not_empty_list = [].__ne__
#  not_empty_list = functools.partial(operator.ne, []))

>>> result = [
        list(filter(not_empty_list, inner_list))
        for inner_list in i 
        if not_empty_list(inner_list)
    ]
>>> result
[[1, 2, 3], [4, 5, 7]]

为了处理像[]这样的列表:
>>> i
[[1, 2, 3, []], [], [], [], [4, 5, [], 7], [[]]]

>>> result = [
        list(filter(not_empty_list, inner_list))
        for inner_list in i 
        if not_empty_list(inner_list)
    ]
>>> list(filter(not_empty_list, result))
[[1, 2, 3], [4, 5, 7]]

2
如果您需要能够处理任意深度嵌套的列表,并且还希望删除例如[[]][[], [[], []]]或其他仅包含(仅包含空列表的)列表的列表,那么这里是一个简单的递归解决方案:
def simplify(value):
  if isinstance(value, list):
    return [y for y in (simplify(x) for x in value) if y != []]
  else:
    return value

print(simplify([[1,2,3,[]],[],[],[],[4,5,[],7],[[],[[]]],[[],[8]]]))

在线尝试!

这个解决方案与迄今为止发布的大多数(全部?)其他递归解决方案的主要区别在于,它首先递归地简化遇到的任何子列表,然后跳过简化后为空的任何子列表。这就是它也能跳过像[[]]这样的子列表的原因。

(请注意,即使给定的列表可能为空,此函数仍将始终返回列表。例如,simplify([[], [[]]])仍将返回[]而不是None。如果您想对简化后顶层列表为空的情况进行一些特殊处理,则需要单独检查该情况。但是,在运行上述函数之后,您可以使用if simplified_list == []来检查该情况。)

2

简单的递归解决方案

a = [[1,2,3,[]],[],[],[],[4,5,[],7]]

def nested_check(alist):
    for item in alist[:]:
        if item == []:
            alist.remove(item)
        elif isinstance(item, list):
            nested_check(item)

nested_check(a)
print(a)

输出:

[[1, 2, 3], [4, 5, 7]]

1
只有在一个列表中嵌套另一个列表时,它才能正常工作。 [1,2,[1,2],3] 如果有更多的列表嵌套在彼此之间,您将需要添加更多的循环。
a = [[1, 2, 3, 0, []], [], [], [], [4, 5, [], 7]]
print('list before:', a)
while [] in a:
    for i in a:
        if i == []:
            a.remove(i)
for i in a:
    for e in i:
        if e == []:
            i.remove(e)
print('list after:', a)

这是我得到的结果:
list before: [[1, 2, 3, 0, []], [], [], [], [4, 5, [], 7]]
list after: [[1, 2, 3, 0], [4, 5, 7]]

-1

您也可以通过过滤“None值”来删除空列表。

尝试:

i = filter(None, i)


-3

从列表中删除空列表

我们可以使用列表推导式方法来解决这个问题。

您可以参考下面的代码

# Initialize list =>
list_1 = [11,20,5,[],7,12,3,[],[],23]

# print list 
print("Original List: "+ str(list_1))

# remove empty list using list comprehension
output = [ i for i in list_1 if i!=[] ] 

# print output
print("list after empty list removed: " + str(output))

输出:

原始列表:[11, 20, 5, [ ], 7, 12, 3, [ ], [ ], 23]

删除空列表后的列表:[11, 20, 5, 7, 12, 3, 23]


这与问题中发布的半解决方案相同,不能解决嵌套列表的问题。 - Charlie Harding

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