一、引子
假设现在有一个句子,我们需要数出其中每个单词出现的次数。
输入:I have an apple, I have a pineapple, I have a banana.
输出:
I 3
a 2
an 1
apple 1
banana 1
have 3
pineapple 1
1、第一种方法
聪明的小伙伴们,是不是马上就想到了?简单,将句子存成字符串,再转换成列表来统计:
1)将字符串s按空格拆分成列表slist
2)对于列表slist的每个元素:
(1)去除非数字和字母,这里尤其是指"," "."等符号
(2)存入字典counts,key为slist的元素,value是出现次数
def count_words_w1(s):
slist = s.split()
counts = dict()
patn = re.compile("W+")
for i in slist:
i = patn.sub("",i)
counts[i] = counts.get(i,0)+1
for k,v in sorted(counts.items()):
print("{0}t{1}".format(k,v))
2、第二种方法
那么如果不转化成列表呢?我们还有别的方法吗?当然有。
对字符串s中每个字符,进行判断:
(1)如果字符是“数字或字母”,则添加到全局变量word尾部
(2)如果字符是“符号或空格”等非数字非字母的形式,则将此时word中保存的单词存入列表counts中
def count_words_w2(s):
slen = len(s)
i = 0
word = ""
counts = dict()
while(i<slen):
if re.match("W+",s[i]):
if word!="":
counts[word] = counts.get(word,0)+1
word = ""
else:
word += s[i]
i+=1
if word !="":
counts[word]= counts.get(word,0)+1
for k,v in sorted(counts.items()):
print("{0}t{1}".format(k,v))
那么问题就来了,第一种方法已经足够简单明了了,为什么还要自找麻烦,使用第二种方法呢?
现在闭上眼睛,假想我们有一个特别特别长的句子,有多长呢?ennnnn,就3G个字符那么长长长好了,此时我们转换成list就会较慢(时间长),list也会特别大(内存大),而第二种方法省略了转成list的步骤,节省了时间,读一个单词处理一个单词,内存开销自然也少了。
3、总结一下
第一种方法思路直观,简单易懂,但当字符串非常大时,运行速度较慢,占用内存较大;
第二种方法相对复杂,代码数较多,但是当字符串较大时,运行速度较快,占用内存较小。
二、扩展
在实际应用中,请大家思考:
如果有一个WES的BED文件(假设已排序),每一行是一条染色体区间(interval),需要将行与行之间有overlap的记录合并成一条记录,该如何设计程序?
——————————————思考让我变聪明的分割线——————————————
第一个思路是将文件存入dict:key为染色体编号,value为各个[start,end]对,然后利用列表顺序,判断overlap并合并(程序略),当BED较大,区间较多时,可以想见这个dict会非常大。
根据上文,我们用第二种方法来尝试一下:
假设我们的输入文件是:
chr1 0 20
chr1 15 35
chr1 40 50
chr2 0 10
chr2 15 30
chr2 25 60
chr3 10 40
则我们期望的输出文件是:
chr1 0 35
chr1 40 50
chr2 0 10
chr2 15 60
chr3 10 40
1)定义全局变量chrid,start,end和merge_region并初始化,chrid,start和end用于存放上一条合并的interval,列表merge_region用于存放所有合并好的intervals;
2)对于BED文件的每一行,判断当前行interval和全局变量代表的interval是否有overlap,如有,overlap等于1,否则overlap等于-1;
3)当BED读入的不是第一行,且overlap等于-1时(如下图黄色行),说明此时的全局变量合并的interval为最大合并区间,并保存到merge_region中,保存到merge_region中之后,不要忘记重置全局变量(见读入此行后的全局变量);
4)如果BED读入的是第一行,或overlap等于1(如下图非黄色的行),此时需扩展intervals,即,取当前行interval和全局变量interval的并集;
5)最后,完成BED文件读入后,不要忘了保存BED文件最后一行的interval.
![9b30a50546ddd1569b7783b096659989.png](https://i-blog.csdnimg.cn/blog_migrate/93ee0eb00802c3c0fad0608b69069ecc.png)
def merge_chr_region(bedfile):
chrid = ""
start = -1
end = -1
merge_region = list()
for line in open(bedfile):
line = line.rstrip()
cur_chr,cur_start,cur_end = line.split()
cur_start = int(cur_start)
cur_end = int(cur_end)
overlap = get_overlap(cur_start,cur_end,start,end) if chrid==cur_chr else -1
if chrid!="" and overlap<=0:
merge_region.append([chrid,start,end])
chrid = cur_chr
start = cur_start
end = cur_end
else:
chrid = cur_chr
start = min(start,cur_start) if start>=0 else cur_start
end = max(end,cur_end)
if chrid != "":
merge_region.append([chrid,start,end])
chrid = ""
for i in range(len(merge_region)):
print("t".join(map(str,merge_region[i])))
def get_overlap(cur_start,cur_end,start,end):
if cur_start<=end and cur_end>=start:
return 1
else:
return -1