【问题标题】:Dual state machine in a List Comprehension列表理解中的双状态机
【发布时间】:2018-04-13 07:44:09
【问题描述】:

考虑以下函数:

def search( seq, start, end ):
    state = 0
    ret = []
    aux = []
    for i in seq:
        if state == 0:
            if i == start:
                aux = [i]
                state = 1
        elif state == 1:
            aux.append(i);
            if i == end:
                ret.append(aux)
                state = 0
    return ret

search() 函数是一个非常基本的双状态机,它返回使用startend 作为分隔符的子列表列表。例如:

DNA = ['CGC','UUC','GCU','UUG','GAA','AAU','UUG','UGU','GUU','UUU','UGU',
       'GGC','UGC','UCG','CUG','CUC','AAA','UUG','UUC','GCU','GCU','UUU',
       'UGU','GUC','CUG','GCU','GCU','UUU','AUU','AUU','AAU','CGC','UGC',
       'UUG','GCG','GUU','CUG','UUA','CGC','UGC','UUG','GGC','UUG','UUG',
       'UGG','CUU','UGG','UUG','UUU','GUA','UAU','UGA','GCU','GUU','CUU',
       'UGG','CUU','UGG','AAU','UUU','GUU','UAU','UAG','GCU','GCU','CUU',
       'GUU','GUU','GUU','GCU','UGU','UGU','AAU','GUU','GGC']


print( search( DNA, start='AAU', end='GUU') )

输出:

[['AAU', 'UUG', 'UGU', 'GUU'], ['AAU', 'CGC', 'UGC', 'UUG', 'GCG', 'GUU'], ['AAU', 'UUU', 'GUU'], ['AAU', 'GUU']]

是否可以使用list comprehension 编写等效函数?

【问题讨论】:

  • 你为什么要这样做?
  • 某种蟒蛇般的感觉促使我有了这种可能性。
  • for 循环是 UN-Pythonic 吗?
  • 这可能是可能的,但我相信它不会很容易理解,只是丑陋。
  • @alvas 不重叠。

标签: python list-comprehension


【解决方案1】:

我不确定理解是完成这项任务的正确工具。但是,你可以写一个非常 Pythonic 的 generator:

def search(seq, start, end):
    ret = []
    for i in seq:
        if i == start or ret:
            ret.append(i)
        if i == end and ret:
            yield ret
            ret = []

>>> list(search(DNA, start='AAU', end='GUU'))
[['AAU', 'UUG', 'UGU', 'GUU'],
 ['AAU', 'CGC', 'UGC', 'UUG', 'GCG', 'GUU'],
 ['AAU', 'UUU', 'GUU'],
 ['AAU', 'GUU']]

如果你真的想要理解,你可以使用takewhiledropwhile的一些骚扰:

 from itertools import takewhile as t, dropwhile as d
 it = iter(DNA)
 [x+[end] for x in (list(t(lambda i: i!=end, d(lambda i: i!=start, it))) for x in range(DNA.count(end))) if x]

虽然这很丑,但我确信它有一些问题 :) 例如,在最后一个 end 之后出现 start...

【讨论】:

    【解决方案2】:

    我认为你想要的是列表的子集,因为它的开始和结束值在列表中找到。 首先,您可以通过以下方式减少搜索空间:

    start_index = seq.index(start)
    end_index = seq.index(end)
    seq[start_index:end_index+1]
    

    然后,您可以在空间内迭代搜索更多的起点和终点。由于没有重叠序列,您可以尝试:

    def search(seq, start, end):
        while start in seq:
            start_index = seq.index(start)
            end_index = seq.index(end) 
            if end_index > start_index:
                yield seq[start_index:end_index+1]
            seq = seq[end_index+1:]
    
    
    
    DNA = ['CGC','UUC','GCU','UUG','GAA','AAU','UUG','UGU','GUU','UUU','UGU',    
           'GGC','UGC','UCG','CUG','CUC','AAA','UUG','UUC','GCU','GCU','UUU',    
           'UGU','GUC','CUG','GCU','GCU','UUU','AUU','AUU','AAU','CGC','UGC',    
           'UUG','GCG','GUU','CUG','UUA','CGC','UGC','UUG','GGC','UUG','UUG',    
           'UGG','CUU','UGG','UUG','UUU','GUA','UAU','UGA','GCU','GUU','CUU',    
           'UGG','CUU','UGG','AAU','UUU','GUU','UAU','UAG','GCU','GCU','CUU',    
           'GUU','GUU','GUU','GCU','UGU','UGU','AAU','GUU','GGC']
    
    start='AAU'
    end='GUU'
    
    list(search(DNA, start='AAU', end='GUU'))
    

    或者(尽管在任何意义上完全“非pythonic”),你可以使用numpy.searchsorted给定开始和结束的索引:

    import numpy as np
    import pandas as pd
    
    DNA = ['CGC','UUC','GCU','UUG','GAA','AAU','UUG','UGU','GUU','UUU','UGU',    
           'GGC','UGC','UCG','CUG','CUC','AAA','UUG','UUC','GCU','GCU','UUU',    
           'UGU','GUC','CUG','GCU','GCU','UUU','AUU','AUU','AAU','CGC','UGC',    
           'UUG','GCG','GUU','CUG','UUA','CGC','UGC','UUG','GGC','UUG','UUG',    
           'UGG','CUU','UGG','UUG','UUU','GUA','UAU','UGA','GCU','GUU','CUU',    
           'UGG','CUU','UGG','AAU','UUU','GUU','UAU','UAG','GCU','GCU','CUU',    
           'GUU','GUU','GUU','GCU','UGU','UGU','AAU','GUU','GGC']
    
    start='AAU'
    end='GUU'
    
    arr = pd.Series(DNA)
    start_indices = arr[arr == start].index
    end_indices = arr[arr == end].index
    for start_idx, end_idx in np.column_stack((start_indices, end_indices[np.searchsorted(end_indices, start_indices, side='right')])):
        print(DNA[start_idx:end_idx+1])
    

    numpyGiven 2 list of integers how to find the non-overlapping ranges?的回答

    【讨论】:

    • 样本数据中有重复项,我猜你必须使用end_index + 1
    猜你喜欢
    • 1970-01-01
    • 2022-01-12
    • 2010-11-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多