这个python代码可以用列表理解来表达吗?

时间:2015-08-31 02:40:37

标签: python list list-comprehension

我发现以下内容完全可读,但是想知道它们是否是一种更加pythonesque的方式来实现它(也许是一个列表理解)?

import re
cgi_keys = [ '_None___total', '_George___total', 'Greg__total', '_Geoff___total', '_Gillian_total' ]
pattern = re.compile(r"_(.+)___(.+)")
totals = []
for key in cgi_keys:
    m = pattern.match(key)
    if m:
        totals.append(m.groups())
totals

将显示:

[('None', 'total'), ('George', 'total'), ('Geoff', 'total')]

但是我希望我能找到一种方法来使用如下构造来获得上述内容:

[key for key in cgi_keys if pattern.match(key)]

以不太有用的形式显示字符串:

['_None___total', '_George___total', '_Geoff___total']

这是否值得尝试将已过滤的字符串分解为元组或列表作为列表理解?

3 个答案:

答案 0 :(得分:2)

这不能直接写为(单个)列表理解而不会为每个元素调用pattern.match(key)两次 - 即

[pattern.match(key) for key in cgi_keys if pattern.match(key)]

但是,您可以使用生成器跳过None元素来移动一些东西:

def skip_none(iter):
    return (i for i in iter if i is not None)

totals = skip_none(pattern.match(key) for key in cgi_keys)

答案 1 :(得分:2)

实际上你可以使用:

totals = (pattern.match(key) for key in cgi_keys)
totals = [match.groups() for match in totals if match]

哪个更短但仍然有效,因为第一个影响是一个生成器,其值不会被评估,直到第二个语句。

另外,您可以使用:

totals = [match.groups for match in filter(None, map(pattern.match, cgi_keys))]

map()给出一个发电机。您必须在Python 2中使用imap。同样适用于ifilter

请注意,如果cgi_keys非常小,您也可以在Python 2中使用map,因为通过迭代两次完成的额外工作无论如何都可能无法察觉。

答案 2 :(得分:0)

您可以在没有正则表达式的情况下执行此操作,并获取列表而不是元组列表。

[[v for v in cgi.split('_') if v] for cgi in cgi_keys]

结果:

[['None', 'total'], ['George', 'total'], ['Greg', 'total'], ['Geoff', 'total'], ['Gillian', 'total']]

但如果你需要元组:

[tuple([v for v in cgi.split('_') if v]) for cgi in cgi_keys]