如何筛选列表中的列表?

时间:2014-09-26 21:56:23

标签: python list filter

我有,例如,listy = [[1,-1,2],[3,-2,-4]]

我想过滤这样我只得到正元素[[1,2],[3]]

这很容易用循环和过滤器(lambda x:x> 0,listy),但我想避免循环。

2 个答案:

答案 0 :(得分:4)

列表推导可以嵌套:

In [2]: [ [i for i in x if i>0] for x in listy ]
Out[2]: [[1, 2], [3]]

关于filter和列表理解之间的选择,Guido van Rossum, the BDFL, wrote列表理解更清晰,更快;

  

滤波器(P,S)几乎总是写得更清楚,因为[x代表S中的x是x   P(x)],这具有最常见用法的巨大优势   涉及比较的谓词,例如x == 42,并定义一个   lambda对于读者来说只需要更多的努力(另外   lambda比列表理解慢。

高级主题:处理大型数据集

如果listy很大并且您的应用程序允许,您可能希望使用生成器来代替列表:

g = ( (i for i in x if i>0) for x in listy )

答案 1 :(得分:2)

你的问题本身就需要一个循环。你想为listy的每个成员做一些事情,for甚至用英语。

但是,你可以将循环包含在理解,或调用map等内。例如:

listy = map(lambda sublist: filter(lambda x: x>0, sublist), listy)
listy = [[x for x in sublist if x>0] for sublist in listy]

(或者,当然,上面的其他两种组合,对filter的理解,或map对理解的理解。)

你也可以懒惰地进行循环,所以不要浪费时间创建过滤后的列表,而只需创建将按需生成正值的迭代器:

itery = itertools.imap(lambda sublist: itertools.ifilter(lambda x: x>0, sublist), listy)
itery = ((x for x in sublist if x>0) for sublist in listy)

但这只是意味着循环发生在以后,当你迭代itery的每个元素时,而不是立即。

(同样,你可以结合上面两个想法,例如,迭代器列表或列表迭代器,而不是迭代器的迭代器或列表列表。)

您甚至可以通过创建一个Python列表的一维数组并在其上调用vectorize(lambda lst: filter(lambda x: x>0, sublist))来隐藏NumPy元素操作中的循环。但循环仍然存在。


当然,您也可以通过循环间接来绕过循环。例如,使用递归:

def filter_nonpositives(x):
    return x[:x[0]>0] + filter_nonpositives(x[1:])

甚至可以将循环展开到最大尺寸:

def filter_nonpositives(x):
    result = []
    if len(x) == 0:
        return result
    if x[0] > 0:
        result.append(x[0])
    if len(x) == 1:
        return result
    if x[1] > 0:
        result.append(x[1])
    if len(x) == 2:
        return result
    if x[2] > 0:
        result.append(x[2])
    # ... repeat as far as you want
    return result

但无论哪种方式,你仍然有效地循环 - 你很难找到任何一个人认为其中任何一个更像Pythonic或更好的人。