如何在Python中对列表内连续M对应数值求和(遇D中断)
合并连续M的数值并实现BAM软剪切转匹配
需求说明
你有若干按「数字+字母」顺序排列的列表,需要将连续出现的M对应的数值求和合并,遇到D则中断当前求和段,示例如下:
输入列表:
['20', 'M', '10', 'M', '1', 'D', '14', 'M', '106', 'M'] ['124', 'M', '19', 'M', '7', 'M'] ['19', 'M', '131', 'M'] ['3', 'M', '19', 'M', '128', 'M'] ['12', 'M', '138', 'M']
期望输出:
['30', 'M', '1', 'D', '120', 'M'] ['150', 'M'] ['150', 'M'] ['150', 'M'] ['150', 'M']
实际业务场景是将BAM文件中的软剪切(S)转为匹配(M),但卡在了数值合并步骤,现有代码片段如下:
#!/usr/bin/python import sys import pysam bamFile = sys.argv[1]; bam = pysam.AlignmentFile(bamFile, 'rb') for read in bam: cigar=read.cigarstring sepa = re.findall('(\\d+|[A-Za-z]+)', cigar) for i in range(len(sepa)): if sepa[i] == 'S': sepa[i] = 'M'
解决方法
1. 核心合并逻辑
通过遍历拆分后的CIGAR列表,维护临时变量累积连续M的数值总和,遇到非M操作时先输出累积结果,再直接添加当前操作;遍历结束后处理剩余的M总和,实现合并逻辑:
def merge_consecutive_m(cigar_parts): result = [] current_m_sum = 0 # 按数字+字母的成对方式遍历 for i in range(0, len(cigar_parts), 2): num = int(cigar_parts[i]) op = cigar_parts[i+1] if op == 'M': current_m_sum += num else: # 先输出累积的M结果(如果有) if current_m_sum > 0: result.append(str(current_m_sum)) result.append('M') current_m_sum = 0 # 添加当前非M操作 result.append(str(num)) result.append(op) # 处理遍历结束后剩余的M总和 if current_m_sum > 0: result.append(str(current_m_sum)) result.append('M') return result
2. 整合到BAM处理代码中
将合并函数加入现有代码,补充缺失的模块导入,完成从S转M到合并连续M的完整流程:
#!/usr/bin/python import sys import pysam import re # 补充导入re模块,原代码未导入但使用了re.findall def merge_consecutive_m(cigar_parts): result = [] current_m_sum = 0 for i in range(0, len(cigar_parts), 2): num = int(cigar_parts[i]) op = cigar_parts[i+1] if op == 'M': current_m_sum += num else: if current_m_sum > 0: result.append(str(current_m_sum)) result.append('M') current_m_sum = 0 result.append(str(num)) result.append(op) if current_m_sum > 0: result.append(str(current_m_sum)) result.append('M') return result bamFile = sys.argv[1] bam = pysam.AlignmentFile(bamFile, 'rb') for read in bam: cigar = read.cigarstring sepa = re.findall('(\\d+|[A-Za-z]+)', cigar) # 将S替换为M for i in range(len(sepa)): if sepa[i] == 'S': sepa[i] = 'M' # 合并连续的M merged_cigar_parts = merge_consecutive_m(sepa) # 转为CIGAR字符串用于后续处理 merged_cigar = ''.join(merged_cigar_parts) # 示例:输出处理后的CIGAR字符串,可根据需求调整逻辑(如写回BAM) print(merged_cigar) bam.close()
代码说明
- 补充
re模块导入:原代码使用re.findall但未导入该模块,需补上。 - 合并函数逻辑:按数字+操作符的成对结构遍历,精准处理连续
M的累积与非M操作的中断输出。 - 完整流程:完成CIGAR拆分、
S转M、连续M合并的全链路处理,最终输出或复用处理后的CIGAR字符串。
内容的提问来源于stack exchange,提问作者fonpe
相关产品推荐
相关产品推荐

