求助:一个字符串查找的问题

wudiliusha 2010-11-13 08:06:18
我们一般查查找字符串个数会使用count函数。如
>>>n='aaaaa'
>>>b='a'
>>>n.count(b)
5
>>>c='aa'
>>>n.count(c)
2
而问题来了,我想要的逐个字符串进行count,比如
n[0:2]=c
n[1:3]=c
n[2:4]=c
n[3:5]=c
所以我想得到的结果其实是4.
知道可以使用循环实现这个效果,但是如果我的n有几千或几个亿的长度的时候效率将非常慢。有没有什么好的方法实现,尽量减少循环次数,因为需要处理的文件很大?
...全文
908 65 打赏 收藏 转发到动态 举报
写回复
用AI写文章
65 条回复
切换为时间正序
请发表友善的回复…
发表回复
yieryi521 2010-11-30
  • 打赏
  • 举报
回复
那个格式有点问题,lz理一下吧
yieryi521 2010-11-30
  • 打赏
  • 举报
回复
统计连着的个数
eg:‘aaaaa’是5个
然后就是cou=4
在统计下一个连着的为 n
cou += (n-1)

def coun(str):
int cou=0
int j=0
for i in str:
if(i='a'):
j=j+1
else:
cou=cou+j-1
j=0
return cou



类似的,如果是3个cou=cou+j-2都可以
希望对你有帮助
wudiliusha 2010-11-24
  • 打赏
  • 举报
回复
[Quote=引用 62 楼 angel_su 的回复:]
引用 60 楼 wudiliusha 的回复:

非常感谢,不过我对c嵌入并不是很熟悉。不过还是非常感谢

如楼上说,我那是c扩展,用c编译器编译出pyd(dll),脚本里直接import就能用。里面有个setup.py傻瓜化执行编译,命令行下python setup.py build即可
[/Quote]
谢谢!辛苦了,还有就是能不能帮我看看这个帖子呢

http://topic.csdn.net/u/20101123/16/a5ab9404-9a7f-45a9-9294-07f0f5a6ebe3.html?20629
angel_su 2010-11-23
  • 打赏
  • 举报
回复
[Quote=引用 60 楼 wudiliusha 的回复:]

非常感谢,不过我对c嵌入并不是很熟悉。不过还是非常感谢
[/Quote]
如楼上说,我那是c扩展,用c编译器编译出pyd(dll),脚本里直接import就能用。里面有个setup.py傻瓜化执行编译,命令行下python setup.py build即可
iambic 2010-11-23
  • 打赏
  • 举报
回复
我看还是用纯C吧,写个通用DLL然后在Python里调用算了。
wudiliusha 2010-11-23
  • 打赏
  • 举报
回复
非常感谢,不过我对c嵌入并不是很熟悉。不过还是非常感谢
wudiliusha 2010-11-22
  • 打赏
  • 举报
回复
[Quote=引用 56 楼 angel_su 的回复:]
用re处理快不了,试试36那附件取代试试:

if j in [1,6,11,16]:
O[j] += mystr.count(line1, N[j])
[/Quote]
你好,我这是2.5.1的,无法导入你的mystr,可以提供未编译的文件吗
angel_su 2010-11-20
  • 打赏
  • 举报
回复
用re处理快不了,试试36那附件取代试试:

if j in [1,6,11,16]:
O[j] += mystr.count(line1, N[j])
wudiliusha 2010-11-19
  • 打赏
  • 举报
回复
[Quote=引用 54 楼 iambic 的回复:]

现在是22s,多久可以令你满意?你能接受用C扩展吗?
[/Quote]
肯定是越快越好,而且现在是30M,大的文件有1G的。只要能提高速度就行,但最好是纯python实现。
iambic 2010-11-18
  • 打赏
  • 举报
回复
现在是22s,多久可以令你满意?你能接受用C扩展吗?
wudiliusha 2010-11-18
  • 打赏
  • 举报
回复
哎呀,忘记贴附件地址了

http://www.box.net/shared/fx8p6gx53l
wudiliusha 2010-11-18
  • 打赏
  • 举报
回复
哎呀,非常对不住大家,刚好前段时间在出差,没有及时看帖,原来这么多热心人,谢谢,谢谢。我现在就把我的代码和需要处理的文件贴出来,大家帮忙看看,主要瓶颈还是我所提问中,我用现在的算法,计算这个30M的文件需要22秒。我的配制是
Inter Core 2 Duo CPU T5870 @2.00GHz
RAM:2.00GB

这是代码


# -*- coding:utf-8 -*-
import time
import re
def getdra(filename):
fh= open(filename,'r')
s = fh.readline()
while s != '':
N = {} #运用字典N将二联核苷酸的种类放入其中
k = 1 #为字典索引定义一个初始值
for i in ['A','C','G','T']: #将四个核苷酸放入i列表中
for j in ['A','C','G','T']: #将四个核苷酸放入j列表中
N[k] = i+j #进行核苷酸的组合
k += 1 #索引加1
O = {} #运用字典O将二联核苷酸的出现的次数放入其中
if s[0] == '>':
print s[:-1]
line=fh.readline()
else:
line=fh.readline()
M = {1:0,2:0,3:0,4:0}
seq_len=0
for j in range(1,17,1): #设置步长1-16
O[j] = 0 #初始化字典的值
last=''
while line and line[0] != '>':
line1 = last+line
seq=line[:-1].upper()
seq_len+=len(seq)
M[1] += seq.count('A') #用count函数获取核苷酸A的数目
M[2] += seq.count('C') #用count函数获取核苷酸C的数目
M[3] += seq.count('G') #用count函数获取核苷酸G的数目
M[4] += seq.count('T') #用count函数获取核苷酸T的数目
for j in range(1,17,1): #设置步长1-16
if j in [1,6,11,16]:
ls=re.compile(N[j]+"+").findall(line1)
O[j]+=len("".join(ls)) - len(ls)
else:
O[j]+=line1.count(N[j])
last=seq[-1:]
line=fh.readline()
T = {} #运用字典T将最终频率结果放入其中
l = 1 #为字典索引定义一个初始值
for i in range(1,5,1): #通过两个嵌套循环实现求值
for j in range(1,5,1):
T[l] = float(O[l]*seq_len)/float(M[i]*M[j]) #根据公式可将T值简化为这个式子,使用float为了浮点输出,默认只保留小数点1位
#即如:(AA出现的次数O[1]*核苷酸总数seq_len)/A的数目(M[1]*A的数目M[1])
l += 1 #索引加1
for i in range(1,17,1): #运用循环将结果输出
print 'T('+N[i]+''')'s value is : '''+ str(T[i])
s = line
f.close()

if __name__ == '__main__':
bt=time.time()
getdra('chr1.fast')
print time.time()-bt
angel_su 2010-11-16
  • 打赏
  • 举报
回复
模块pyd文件链接在下面,有兴趣的可以试试,用的时候:
import mystr
mystr.count(thestr, substr)

http://d.namipan.com/d/4875ff3fe103c610a5952c6a83031631fc1b63cd00260000
angel_su 2010-11-16
  • 打赏
  • 举报
回复
[Quote=引用 31 楼 i_nbfa 的回复:]

引用 29 楼 angel_su 的回复:
问题是你怎么找呢?我程序一直在解决这个问题
[/Quote]
找最小的步进就可以吧,我用cython写了个简单c扩展,照你的搬套,c的strstr就是find,memcmp等同切片比较。蛋疼1的步进在c里是指针自加,不调用函数嘛应该快过其他情况,试验一亿个连续x里找xx用0.3秒杀,不连续反而慢...
cdef extern from *:
char *strstr(char *str1, char *str2)
int memcmp(char *str1, char *str2, int n)
int strlen(char *str )

def count(char *s1, char *s2):
cdef char *curr
cdef int i, cnt, step

if strlen(s1) == 0 or strlen(s2) == 0:
return 0

# 分析重叠找最小步进
step = strlen(s2)
for i in range(step):
if memcmp(s2, s2+i, step-i) == 0:
step = i
break

# 分2支,单字符不调用strstr()
cnt , curr = 0, s1
if step == 1:
while True:
curr = strstr(curr, s2)
if curr == NULL:
break
cnt = cnt + 1
curr = curr + strlen(s2)
while curr[0] == s2[0]:
cnt = cnt + 1
curr = curr +1
else:
while True:
curr = strstr(curr, s2)
if curr == NULL:
break
cnt= cnt + 1
curr = curr + step

return cnt
iambic 2010-11-16
  • 打赏
  • 举报
回复
这样说吧,使用find的算法,其实是两重循环,即使你在外面的循环没有算到结尾,find内部的循环也已经算到了字符串结尾,同样是算了差不多10000 * 10000次。
显式startswith是把两个循环合成一个了,从算法复杂度来讲是没有区别的。
至于break,不是关键,你两重循环,break了一次,我一重循环,为什么要break。
I_NBFA 2010-11-16
  • 打赏
  • 举报
回复
觉得真没必要再照搬我的程序了,重复字符6L效率大同小异。
30L的重点也无非是找到非重复字符,mystr = "ab" * 10000 * 10000, sub = "ab"运行6L看看差多少?
110倍!! 当然测试数据比较蛋疼,谁会这么虐"ab"? 输入量也不可能总是这么巨大。所以6L程序就可以了。
I_NBFA 2010-11-16
  • 打赏
  • 举报
回复
[Quote=引用 42 楼 iambic 的回复:]
从算法来讲,find本身就是一个使用了startswith的循环。find失败也是因为循环使用startswith到尾了。别包装了下就不认识了啊……
[/Quote]
我说的不是find本身的算法,find也许内部使用startswith,但startswith无法break;
my = "a" * 10000 * 10000, sub = "ab", find最多遍历一次break,
但用startswith要10000 * 10000 - len(sub) + 1次,效率天壤之别。我是这个意思。
iambic 2010-11-16
  • 打赏
  • 举报
回复
从算法来讲,find本身就是一个使用了startswith的循环。find失败也是因为循环使用startswith到尾了。别包装了下就不认识了啊……
I_NBFA 2010-11-16
  • 打赏
  • 举报
回复
find和startswith怎么会一样呢?前者可以直接找到尾,后者只找sub那么长,5L程序就没办法在find
失败时直接break,6L可以,所以5L永远是一个一个把mystr找干净。
加载更多回复(44)

37,721

社区成员

发帖
与我相关
我的任务
社区描述
JavaScript,VBScript,AngleScript,ActionScript,Shell,Perl,Ruby,Lua,Tcl,Scala,MaxScript 等脚本语言交流。
社区管理员
  • 脚本语言(Perl/Python)社区
  • IT.BOB
加入社区
  • 近7日
  • 近30日
  • 至今

试试用AI创作助手写篇文章吧