我希望从列表中删除一个包含'X'
或'N'
的元素。我需要对大型基因组进行操作。以下是一个例子:
输入:
codon=['AAT','XAC','ANT','TTA']
预期输出:
codon=['AAT','TTA']
我希望从列表中删除一个包含'X'
或'N'
的元素。我需要对大型基因组进行操作。以下是一个例子:
输入:
codon=['AAT','XAC','ANT','TTA']
codon=['AAT','TTA']
基础目的
>>> [x for x in ['AAT','XAC','ANT','TTA'] if "X" not in x and "N" not in x]
['AAT', 'TTA']
如果你有大量的数据,我建议你使用字典或集合
如果除了X和N还有许多其他字符,你可以这样做
>>> [x for x in ['AAT','XAC','ANT','TTA'] if not any(ch for ch in list(x) if ch in ["X","N","Y","Z","K","J"])]
['AAT', 'TTA']
注意: list(x)
可以简写为 x
,["X","N","Y","Z","K","J"]
可以简写为 "XNYZKJ"
,并参考 gnibbler 的答案,他做得最好。
>>> [x for x in ['AAT','XAC','ANT','TTA'] if not any(y in x for y in "XN")]
['AAT', 'TTA']
>>> [x for x in ['AAT','XAC','ANT','TTA'] if not set("XN")&set(x)]
['AAT', 'TTA']
codon = ['AAT','XAC','ANT','TTA']
def pred(s,memo={}):
if s not in memo:
memo[s]=not any(y in s for y in "XN")
return memo[s]
print filter(pred,codon)
codon = ['AAT','XAC','ANT','TTA']
def pred(s,memo={}):
if s not in memo:
memo[s]= not set("XN")&set(s)
return memo[s]
print filter(pred,codon)
pred
的代码可以利用内置的 dict.setdefault
方法(正如我的答案所示);我猜想 setdefault
版本会更快。 - Eric O. Lebigotif not s is memo
并将memo[s] =
移动到其块中来删除冗余的return
语句。 - Ben Blank lst = filter(lambda x: 'X' not in x and 'N' not in x, list)
>>> def pred(item, haystack="XN"):
... return any(needle in item for needle in haystack)
...
>>> lst = ['AAT', 'XAC', 'ANT', 'TTA']
>>> idx = 0
>>> while idx < len(lst):
... if pred(lst[idx]):
... del lst[idx]
... else:
... idx = idx + 1
...
>>> lst
['AAT', 'TTA']
我知道列表推导式现在很流行,但如果列表很长,我们不想没有任何理由地重复它,对吧?你可以将其带到下一个步骤并创建一个好用的实用函数:
>>> def remove_if(coll, predicate):
... idx = len(coll) - 1
... while idx >= 0:
... if predicate(coll[idx]):
... del coll[idx]
... idx = idx - 1
... return coll
...
>>> lst = ['AAT', 'XAC', 'ANT', 'TTA']
>>> remove_if(lst, pred)
['AAT', 'TTA']
>>> lst
['AAT', 'TTA']
not
和and
在一起隐藏了你真正在做什么。与其从列表中删除几个项目,不如看到没有项目的列表副本。我想我更喜欢简单和清晰。 - D.Shawleyidx = idx - 1
。使用列表推导式或 filter() 的原因是循环在 C 中,所以通常更快。 - John La RooyO(n^2)
,而获取一个新的过滤列表并用新列表替换旧列表的内容则为O(n)
。 - eadfilter(lambda x: 'N' not in x or 'X' not in x, your_list)
your_list = [x for x in your_list if 'N' not in x or 'X' not in x]
'N'不在x中且'X'不在x中
,或者是not ('N' in x or 'X' in x)
。 - Lee D我非常喜欢gnibbler的记忆化方法。在大数据集上,使用记忆化的任一方法应该是完全相同的快速,因为记忆字典应该很快就会被填满,实际测试应该很少进行。考虑到这一点,我们应该能够进一步提高大数据集的性能。(这对于非常小的数据集来说有一些成本,但谁关心那些呢?)以下代码只需要在存在时查找一次记忆字典中的项目,而不是两次(一次确定成员身份,另一次提取值)。
codon = ['AAT', 'XAC', 'ANT', 'TTA']
def pred(s,memo={}):
try:
return memo[s]
except KeyError:
memo[s] = not any(y in s for y in "XN")
return memo[s]
filtered = filter(pred, codon)
如我所说,如果基因组很大(或者至少不是极小),这应该会更快。
如果您不想复制列表,而只是遍历过滤后的列表,请执行以下操作:
for item in (item for item in codon if pred):
do_something(item)
itertools.ifilter
,例如:new_seq = itertools.ifilter(lambda x: 'X' in x or 'N' in x, seq)
这实际上推迟了对列表中每个元素的测试,直到您实际迭代它。请注意,您可以像原始序列一样过滤已过滤的序列:
new_seq1 = itertools.ifilter(some_other_predicate, new_seq)
编辑:
另外,一些测试表明,在集合中记忆找到的条目很可能提供足够的改进,值得这样做,并且使用正则表达式可能不是正确的方法:
seq = ['AAT','XAC','ANT','TTA']
>>> p = re.compile('[X|N]')
>>> timeit.timeit('[x for x in seq if not p.search(x)]', 'from __main__ import p, seq')
3.4722548536196314
>>> timeit.timeit('[x for x in seq if "X" not in x and "N" not in x]', 'from __main__ import seq')
1.0560532134670666
>>> s = set(('XAC', 'ANT'))
>>> timeit.timeit('[x for x in seq if x not in s]', 'from __main__ import s, seq')
0.87923730529996647
list(new_seq)
就能做到这一点——但它会访问列表中的每个元素来实现转换。如果你正在处理数百万个密码子的列表,你真的只想这样做一次。 - Robert Rossneyfrom typing import TypeVar, Callable, List
T = TypeVar("T")
def list_remove_first(lst: List[T], accept: Callable[[T], bool]) -> None:
for i, v in enumerate(lst):
if accept(v):
del lst[i]
return
def list_remove_all(lst: List[T], accept: Callable[[T], bool]) -> None:
for i in reversed(range(len(lst))):
if accept(lst[i]):
del lst[i]
如S.Mark所请求,这是我的版本。它可能会慢一些,但可以更轻松地更改所删除的内容。
def filter_genome(genome, killlist = set("X N".split()):
return [codon for codon in genome if 0 == len(set(codon) | killlist)]
&
,而不是|
。 - Lee D使用正则表达式在同一字符串中搜索某个字符比多次搜索快得多(渐进地):实际上,使用正则表达式时,序列最多只需读取一次(而不是像gnibbler的原始答案中未找到字母时需要读取两次)。通过gnibbler的记忆化,正则表达式方法的读取如下:
import re
remove = re.compile('[XN]').search
codon = ['AAT','XAC','ANT','TTA']
def pred(s,memo={}):
if s not in memo:
memo[s]= not remove(s)
return memo[s]
print filter(pred,codon)
这应该比使用“in s”或“set”检查(即,对于足够长的字符串s
,上面的代码应该更快)更快(渐近地)。
我最初认为gnibbler的答案可以用dict.setdefault()更快、更紧凑地编写:
codon = ['AAT','XAC','ANT','TTA']
def pred(s,memo={}):
return memo.setdefault(s, not any(y in s for y in "XN"))
print filter(pred,codon)
然而,正如gnibbler所指出的那样,setdefault中的值始终会被评估(尽管原则上,它只能在未找到字典键时评估)。