是否可以添加具有列表理解功能的where子句? [英] Is it possible to add a where clause with list comprehension?

查看:93
本文介绍了是否可以添加具有列表理解功能的where子句?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

请考虑以下列表理解

[ (x,f(x)) for x in iterable if f(x) ]

这将基于条件f过滤可迭代对象,并返回x,f(x)对.这种方法的问题是f(x)被计算两次. 如果我们能像这样写,那就太好了

This filters the iterable based a condition f and returns the pairs of x,f(x). The problem with this approach is f(x) is calculated twice. It would be great if we could write like

[ (x,fx) for x in iterable if fx where fx = f(x) ]
or
[ (x,fx) for x in iterable if fx with f(x) as fx ]

但是在python中,我们必须使用嵌套理解来编写代码,以避免重复调用f(x),这会使理解变得不太清晰

But in python we have to write using nested comprehensions to avoid duplicate call to f(x) and it makes the comprehension look less clear

[ (x,fx) for x,fx in ( (y,f(y) for y in iterable ) if fx ]

还有其他方法可以使其更具Python可读性吗?

Is there any other way to make it more pythonic and readable?

更新

Python 3.8即将推出! PEP

Coming soon in python 3.8! PEP

# Share a subexpression between a comprehension filter clause and its output
filtered_data = [y for x in data if (y := f(x)) is not None]

推荐答案

您希望在python列表理解中具有let -statement语义,其范围可用于___ for..in(map)和if ___ (过滤器)部分,其范围取决于..for ___ in....

You seek to have let-statement semantics in python list comprehensions, whose scope is available to both the ___ for..in(map) and the if ___(filter) part of the comprehension, and whose scope depends on the ..for ___ in....

您的解决方案,已修改: 您的[ (x,fx) for x,fx in ( (y,f(y) for y in iterable ) if fx ]解决方案(您承认不可读)是最优化的写法.

Your solution, modified: Your (as you admit unreadable) solution of [ (x,fx) for x,fx in ( (y,f(y) for y in iterable ) if fx ] is the most straightforward way to write the optimization.

主要思想:将x提升到元组(x,f(x)).

Main idea: lift x into the tuple (x,f(x)).

有人会认为,最"Python式"的做事方式将是原始的[(x,f(x)) for x in iterable if f(x)]并接受效率低下的情况.

Some would argue the most "pythonic" way to do things would be the original [(x,f(x)) for x in iterable if f(x)] and accept the inefficiencies.

但是,如果您打算做很多事,可以将((y,fy) for y in iterable)分解为一个函数.这很糟糕,因为如果您希望访问的变量多于x,fx(例如x,fx,ffx),那么您将需要重写所有列表推导.因此,除非您确定只需要x,fx并计划重用此模式,否则这不是一个很好的解决方案.

You can however factor out the ((y,fy) for y in iterable) into a function, if you plan to do this a lot. This is bad because if you ever wish to have access to more variables than x,fx (e.g. x,fx,ffx), then you will need to rewrite all your list comprehensions. Therefore this isn't a great solution unless you know for sure you only need x,fx and plan to reuse this pattern.

生成器表达式:

主要思想:对生成器表达式使用更复杂的替代方法:使用python可以让您编写多行代码.

Main idea: use a more complicated alternative to generator expressions: one where python will let you write multiple lines.

您可以只使用生成器表达式,该表达式可以很好地与python配合使用:

You could just use a generator expression, which python plays nicely with:

def xfx(iterable):
    for x in iterable:
        fx = f(x)
        if fx:
            yield (x,fx)

xfx(exampleIterable)

这就是我个人要做的方式.

This is how I would personally do it.

记住/缓存:

主要思想:您还可以使用(滥用吗?)副作用并使f具有全局备注缓存,因此您无需重复操作.

Main idea: You could also use(abuse?) side-effects and make f have a global memoization cache, so you don't repeat operations.

这可能会产生一些开销,并且需要一个策略来确定缓存应该有多大以及何时应该对其进行垃圾回收.因此,仅当您有其他用途来记忆f或f非常昂贵时,才应使用此方法.但这会让你写...

This can have a bit of overhead, and requires a policy of how large the cache should be and when it should be garbage-collected. Thus this should only be used if you'd have other uses for memoizing f, or if f is very expensive. But it would let you write...

[ (x,f(x)) for x in iterable if f(x) ]

...就像您最初想要的那样,即使在技术上两次调用它,也不会在f中执行两次昂贵的操作而降低性能.您可以将@memoized装饰器添加到f:示例(不使用最大缓存)尺寸).只要x是可哈希值(例如,数字,元组,frozenset等),这将起作用.

...like you originally wanted without the performance hit of doing the expensive operations in f twice, even if you technically call it twice. You can add a @memoized decorator to f: example (without maximum cache size). This will work as long as x is hashable (e.g. a number, a tuple, a frozenset, etc.).

虚拟值:

主要思想:在一个闭包中捕获fx = f(x)并修改列表理解的行为.

Main idea: capture fx=f(x) in a closure and modify the behavior of the list comprehension.

filterTrue(
    (lambda fx=f(x): (x,fx) if fx else None)() for x in iterable
)

其中filterTrue(iterable)是filter(无,可迭代).如果您的列表类型(一个2元组)实际上能够被None修改,则必须对此进行修改.

where filterTrue(iterable) is filter(None, iterable). You would have to modify this if your list type (a 2-tuple) was actually capable of being None.

这篇关于是否可以添加具有列表理解功能的where子句?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆