计算子串

时间:2018-02-06 03:40:02

标签: python string python-3.x

我有一些字符串

str = 'kkyykykyyk'

我想知道在这个字符串中出现“kyy”和“ky”的次数。 但是,如果某些内容像本例中那样重叠,那么我只需要计算更长的子字符串。

Mu当前解决方案看起来像这样

k = str.count('kyy') 
y = (str.count('ky') - str.count('kyy'))
print(k, y)        # solution: 'kyy' two times AND 'ky' one time

这个问题是否有更短或更“蟒蛇”的方法?

4 个答案:

答案 0 :(得分:4)

一种方法是使用正则表达式并使用?运算符来检查字符串中是否出现额外的y。

也就是说,我们发现ky的出现,并检查下一个值是y是否发生我们接受其他我们不

>>> import re
>>> st = 'kkyykykyyk'
>>> re.findall(r'kyy?',st)
['kyy', 'ky', 'kyy']
>>> re.findall(r'kyy?',st).count('kyy')
2
>>> re.findall(r'kyy?',st).count('ky')
1

答案 1 :(得分:2)

这是一种方法。拆分'kyy'。结果数组的长度 - 1是'kyy'出现的次数。然后通过再次连接和分割来计算结果数组中'ky'的出现次数。

更新

正如@Windygound指出的那样,如果字符串中没有出现'kyy'(没有要拆分)或者字符串中有其他字母(即{{1} }})。这是一个解决方法:

'kkyykyakyyk'

另外,请避免将变量# original example s = 'kkyykykyyk' print(s.split('kyy')) #['k', 'ky', 'k'] # solution arr = s.split('kyy') print(len(arr)-1, len(" ".join(arr).split('ky'))-1) 命名为内置类型。

更新2

速度测试结果表明OP的代码实际上是最快的。可以通过在注释中使用@ wim的建议来重新使用变量str来改进它。

定义功能

k

制作一些随机测试数据

# OP's solution
def count_ky(s):
    k = s.count('kyy') 
    y = (s.count('ky') - s.count('kyy'))
    return (k, y)

# OP's solution with @wim's suggestion
def count_ky2(s):
    k = s.count('kyy') 
    y = (s.count('ky') - k)
    return (k, y)

def count_ky_nathan(s):
    k, y = 0, 0
    for place in range(len(s)):
        if s[place:].startswith('kyy'):
            k += 1
        elif s[place:].startswith('ky'):
            y += 1
    return (k, y)

def count_ky_pault(s):
    arr = s.split('kyy')
    k = len(arr)-1
    y = len(" ".join(arr).split('ky'))-1
    return (k, y)

def count_ky_albin(s):
    k = re.findall(r'kyy?',s).count('kyy')
    y = re.findall(r'kyy?',s).count('ky')
    return (k, y)

验证结果匹配

import random
import string
N = 1000

# pick from the letters k, y, and x
test_words = [
    ''.join(random.choice(['k', 'y', 'x']) for _ in range(random.randint(10,30)))
    for _ in range(N)
]

速度测试

我遗漏了@ Nathan的第三个解决方案(怪异的一个),因为它没有正确的计数。

test_funcs = [count_ky, count_ky2, count_ky_nathan, count_ky_pault, count_ky_albin,
              count_ky_nathan2]
for tf in test_funcs:
    print reduce(lambda x, y: [x[i]+y[i] for i in range(2)], [tf(s) for s in test_words])
#[687, 1424]
#[687, 1424]
#[687, 1424]
#[687, 1424]
#[687, 1424]
#[687, 1424]

答案 2 :(得分:0)

为了计算较长的子串实例,我会用一些在我想要查看的数据中无效的字符替换子字符串。然后重复每个连续的子串。

string =  'kkyykykyyk'
substrings = {'kyy': 0, 'ky': 0}
for sub, val in substrings.items():
    index = string.find(sub)
    while index != -1:
        val += 1
        string = string[:index] + '###' + string[index + len(sub):]
        index = string.find(sub)
substrings[sub] = val

可以将字符串和字典打印为

k#########k
{'kyy': 2, 'ky': 1}

答案 3 :(得分:0)

尝试简洁易读而不聪明,因为对我来说,#pythonic"非常关注可读性:

s = 'kkyykykyyk'
k, y = 0, 0
for place in range(len(s)):
    if s[place:].startswith('kyy'):
        k += 1
    elif s[place:].startswith('ky'):
        y += 1

对于聪明和简短,我喜欢@ pault的分裂和计数方法的这种变化:

parts = s.split('kyy')
k = len(parts) - 1
y = sum(p.count('ky') for p in parts)

最后一个奇怪的,只是为了好玩:

nokyy = s.replace('kyy', ' ') # replace with ' ' so we don't create new matches!
noky = nokyy.replace('ky', '')
k = (len(s) - len(nokyy))//2
y = (len(nokyy) - len(noky))//2