给出以下列表:
DNA_list = ['ATAT', 'GTGTACGT', 'AAAAGGTT']
我想过滤超过3个字符的字符串。我用以下代码实现了这个目标:
使用for循环:
long_dna = []
for element in DNA_list:
length = len(element)
if int(length) > 3:
long_dna.append(element)
print long_dna
但是我希望我的代码更通用,所以我以后可以过滤任何长度的字符串,所以我使用了一个函数和for循环:
def get_long(dna_seq, threshold):
return len(dna_seq) > threshold
long_dna_loop2 = []
for element in DNA_list:
if get_long(element, 3) is True:
long_dna_loop2.append(element)
print long_dna_loop2
我希望使用filter()
实现相同的通用性,但我无法做到这一点。如果我使用上面的函数get_long()
,当我将它与filter()
一起使用时,我就无法将参数传递给它。这是不可能还是有办法绕过它?
我的代码filter()
用于特定情况:
def is_long(dna):
return len(dna) > 3
long_dna_filter = filter(is_long, DNA_list)
答案 0 :(得分:15)
使用lambda
提供阈值,如下所示:
filter(lambda seq: get_long(seq, 3),
dna_list)
答案 1 :(得分:15)
你要做的事情被称为partial function application:你有一个带有多个参数的函数(在这种情况下,2)并且希望得到一个从它派生的函数,并修复了一个或多个参数,你然后可以转到filter
。
某些语言(特别是功能性语言)具有此功能"内置"。在python中,您可以使用lambdas来执行此操作(正如其他人所示)或您可以使用functools
library。特别是functools.partial
:
partial()用于部分函数应用程序,它“冻结”函数参数和/或关键字的某些部分,从而产生具有简化签名的新对象。例如,partial()可用于创建一个callable,其行为类似于int()函数,其中base参数默认为2:
>>> from functools import partial >>> basetwo = partial(int, base=2) >>> basetwo.__doc__ = 'Convert base 2 string to an int.' >>> basetwo('10010') 18
所以你可以这样做:
filter(functools.partial(get_long, treshold=13), DNA_list)
答案 2 :(得分:10)
您需要使用filter()
吗?为什么不使用更多的Pythonic列表理解?
示例:
>>> DNA_list = ['ATAT', 'GTGTACGT', 'AAAAGGTT']
>>> threshold = 3
>>> long_dna = [dna_seq for dna_seq in DNA_list if len(dna_seq) > threshold]
>>> long_dna
['ATAT', 'GTGTACGT', 'AAAAGGTT']
>>> threshold = 4
>>> [dna_seq for dna_seq in DNA_list if len(dna_seq) > threshold]
['GTGTACGT', 'AAAAGGTT']
这种方法的优点是可以将它转换为生成器,这可以根据您的应用提供改进的内存和执行,例如:如果你有很多DNA序列,并且你想迭代它们,那么将它们作为一个列表来实现会一次消耗大量的内存。等效生成器只需要用方括号[]
替换方括号()
:
>>> long_dna = (dna_seq for dna_seq in DNA_list if len(dna_seq) > threshold)
<generator object <genexpr> at 0x7f50de229cd0>
>>> list(long_dna)
['GTGTACGT', 'AAAAGGTT']
在Python 2中,这种性能改进不是filter()
的选项,因为它返回一个列表。在Python 3中filter()
返回一个更类似于生成器的过滤器对象。
答案 3 :(得分:4)
你可以让is_long
返回一个可以接受dna
的函数,就像这样
>>> def is_long(length):
... return lambda dna: len(dna) > length
...
然后在filter
中使用它,就像这样
>>> filter(is_long(3), DNA_list)
['ATAT', 'GTGTACGT', 'AAAAGGTT']
>>> filter(is_long(4), DNA_list)
['GTGTACGT', 'AAAAGGTT']
注意:请勿使用is
运算符来比较布尔值或数字。而是尽可能地依赖数据的真实性。所以,在你的情况下,你可以编写你的第二个版本
if get_long(element, 3):
long_dna_loop2.append(element)
引用programming recommendations in PEP-8,
不要使用==。
将布尔值与True或False进行比较Yes: if greeting: No: if greeting == True: Worse: if greeting is True:
答案 4 :(得分:0)
以下是使用lambda
的更多方法。第一个使用默认关键字参数来保持所需的长度。第二个只是在lambda
正文中嵌入所需的长度。
#Create a list of strings
s = 'abcdefghi'
data = [s[:i+1] for i in range(len(s))]
print data
thresh = 3
print filter(lambda seq, n=thresh: len(seq) > n, data)
print filter(lambda seq: len(seq) > 5, data)
<强>输出强>
['a', 'ab', 'abc', 'abcd', 'abcde', 'abcdef', 'abcdefg', 'abcdefgh', 'abcdefghi']
['abcd', 'abcde', 'abcdef', 'abcdefg', 'abcdefgh', 'abcdefghi']
['abcdef', 'abcdefg', 'abcdefgh', 'abcdefghi']
在第一个例子中你也可以这样做:
print filter(lambda seq, n=3: len(seq) > n, data)
同样,在第二个示例中,您可以使用本地(或全局)变量替换文字5
,例如:
thresh = 5
print filter(lambda seq: len(seq) > thresh, data)
答案 5 :(得分:0)
您总是可以创建一个callable,它返回一个适用于filter
完成的比较的callable,如下例所示:
def main():
dna_list = ['A', 'CA', 'TGATGATAC', 'GGGTAAAATC', 'TCG', 'AGGTCGCT', 'TT',
'GGGTTGGA', 'C', 'TTGGAGGG']
print('\n'.join(filter(length_at_least(3), dna_list)))
def length_at_least(value):
return lambda item: len(item) >= value
# length_at_least = lambda value: lambda item: len(item) >= value
if __name__ == '__main__':
main()
答案 6 :(得分:0)
你可以有更一般的案例。
由于函数是python中的一个对象,你可以创建另一个函数,它返回你想要的函数。
def f(threshhold):
def g(x):
return len(x)>threshhold
return g #return a function
this_function = f(3)
DNA_list = ['ATAT', 'GTGTACGT', 'AAAAGGTT','AAA','AAAA']
filter(this_function, DNA_list)
output: ['ATAT', 'GTGTACGT', 'AAAAGGTT', 'AAAA']
g是你真正想要的,f是创造它的功能。
答案 7 :(得分:0)
我使用了如下内部函数和非本地范围的不同解决方案。由于我的代码不同,我已经修改了原始代码以供理解。
希望这会有所帮助。 :)
def outerfun():
charlimit = 3
def is_long(dna):
nonlocal charlimit
return len(dna) > charlimit
long_dna_filter = filter(is_long, DNA_list)
return long_dna_filter