我将以下函数作为脚本inspired by this的一部分:
def view(a='', b='', c=''):
if a=='All' and b=='All' and c=='All': return df
if a=='All' and c=='All' and b!='All': return df[(df['b']==b)]
if a!='All' and c=='All' and b=='All': return df[(df['a']==a)]
if a=='All' and c!='All' and b=='All': return df[(df['c']==c)]
if a=='All' and c!='All' and b!='All': return df[(df['c']==c) & (df['b']==b)]
if a!='All' and c=='All' and b!='All': return df[(df['a']==a) & (df['b']==b)]
if a!='All' and c!='All' and b=='All': return df[(df['a']==a) & (df['c']==c)]
return df[(df['a']==a) & (df['b']==b) & (df['c']==c)]
有没有一种很好的方法来编写带有一个漂亮的pythonic表达式的所有链接if语句。如果对n个变量进行推广,则给出答案。
注意: Perhaps related to this question,但我仍然无法弄明白。
答案 0 :(得分:0)
你的功能基本上是这样做的:
if all parameters are 'All':
return df
else:
Take all the non-'All' parameters
Test if each one is equal to df['name_of_parameter']
Bitwise-AND them together
Return df[result of previous line]
让我们首先列出所有非'全部'参数:
notall = [x for x in [a,b,c] if x != 'All']
if not notall:
return df
else:
???
障碍#1:我们现在已经忘记了哪个值与哪个参数相关。为什么我们需要知道?这样我们就可以将参数与df
的正确元素进行比较。我们可以通过不仅存储参数来解决这个问题。 notall
中的值以及它们的名称:
notall = [(x, name) for (x, name) in [(a, 'a'), (b, 'b'), (c, 'c')] if x != 'All']
if not notall:
return df
else:
???
两次写出每个参数的名称很难看,但它要么是这个,要么是locals
和/或**kwargs
的顽皮。
通过这种方式,对df
元素的比较很容易:
compared = [df[name] == x for (x, name) in notall]
现在,我们如何和他们在一起?我们可以使用functools.reduce()
和operator.and_
,但是(除非您重载==
以返回非布尔值,我希望您没有这样做),元素compared
都是布尔值,这意味着将它们与按位AND组合与将它们与逻辑AND组合相同,并且Python已经具有以下功能:all()
。
return df[all(compared)]
全部放在一起:
def view(a='', b='', c=''):
notall = [(x, name) for (x, name) in [(a, 'a'), (b, 'b'), (c, 'c')] if x != 'All']
if not notall:
return df
else:
compared = [df[name] == x for (x, name) in notall]
return df[all(compared)]
或者,更紧凑:
def view(a='', b='', c=''):
notall = [(x, name) for (x, name) in [(a, 'a'), (b, 'b'), (c, 'c')] if x != 'All']
if not notall:
return df
else:
return df[all(df[name] == x for (x, name) in notall)]
现在,关于前面提到的那种顽皮:如果所有参数都在dict
中,那么notall
可以只包含键,这样我们就可以查找参数值和{ {1}}值而不重复(太多)。我们如何获得df
中的所有参数?使用dict
:
**kwargs
(请注意使用def view(**kwargs):
notall = [name for name in NAMES if kwargs.get(name, '') != 'All']
为参数提供默认值。)但get
应该是什么?它不能是NAMES
,因为它只包含用户传入的参数,这些参数可能不是全部参数(甚至可能包含我们不期望的密钥!)。选项1是在某处写出参数名称列表并使用:
kwargs.keys()
或者,如果NAMES = ['a', 'b', 'c']
的键恰好与函数参数的所需名称相同,我们可以使用df
:
df.keys()
或略短:
notall = [name for name in df.keys() if kwargs.get(name, '') != 'All']
在此之后,我们只需要更新 notall = [name for name in df if kwargs.get(name, '') != 'All']
元素的使用方式,改变这一点:
notall
到此:
return df[all(df[name] == x for (x, name) in notall)]
(请注意,我们仍需要继续使用return df[all(df[name] == kwargs.get(name, '') for name in notall)]
来设置默认值。)
将它们全部重新组合在一起:
get
或者,如果参数名称与NAMES = ['a', 'b', 'c']
def view(**kwargs):
notall = [name for name in NAMES if kwargs.get(name, '') != 'All']
if not notall:
return df
else:
return df[all(df[name] == kwargs.get(name, '') for name in notall)]
的键相同:
df
编辑:基于以下评论,显然def view(**kwargs):
notall = [name for name in df if kwargs.get(name, '') != 'All']
if not notall:
return df
else:
return df[all(df[name] == kwargs.get(name, '') for name in notall)]
的值会覆盖df
,因此它不会返回布尔值。幸运的是,如上所述,这只需要改变这一点:
==
到此:
return df[all(df[name] == kwargs.get(name, '') for name in notall)]
答案 1 :(得分:0)
这应该可以解决问题:
import itertools, functools
from operator import eq, ne, and_
def view(*args):
Eq, Ne = functools.partial(eq, 'All'), functools.partial(ne, 'All')
if all(Eq(var) for var in args):
return df
for cond, ret in itertools.product((Eq, Ne), len(args)):
if all(fun(var) for var, fun in zip(args, cond)):
index = functools.reduce(and_, (df[var] == var for var, fun in cond if fun == Ne))
return df[index]
唯一的问题是我没有简单的方法知道您当前正在使用的变量的名称。这就是我使用df[var] == var
的原因。
例如,通过使每个变量都带有它的名称,这相对容易修复。因此,基本上,每个变量都是一个元组a = (variable, "variable")
。