簡體   English   中英

計算連續字符

[英]Count consecutive characters

如何計算 Python 中的連續字符,以查看每個唯一數字在下一個唯一數字之前重復的次數?

起初,我以為我可以做類似的事情:

word = '1000'

counter = 0
print range(len(word))

for i in range(len(word) - 1):
    while word[i] == word[i + 1]:
        counter += 1
        print counter * "0"
    else:
        counter = 1
        print counter * "1"

這樣我就可以看到每個唯一數字重復的次數。 但是,當i達到最后一個值時,這當然超出了范圍。

在上面的示例中,我希望 Python 告訴我 1 重復 1,而 0 重復 3 次。 但是,由於我的while語句,上面的代碼失敗了。

我怎么能只用內置函數來做到這一點?

連續計數:

哦,還沒有人發布itertools.groupby

s = "111000222334455555"

from itertools import groupby

groups = groupby(s)
result = [(label, sum(1 for _ in group)) for label, group in groups]

之后, result如下:

[("1": 3), ("0", 3), ("2", 3), ("3", 2), ("4", 2), ("5", 5)]

您可以使用以下格式進行格式化:

", ".join("{}x{}".format(label, count) for label, count in result)
# "1x3, 0x3, 2x3, 3x2, 4x2, 5x5"

總數:

評論中有人擔心你想要一個數字總數,所以"11100111" -> {"1":6, "0":2} 在這種情況下,您想使用collections.Counter

from collections import Counter

s = "11100111"
result = Counter(s)
# {"1":6, "0":2}

你的方法:

正如許多人指出的那樣,您的方法失敗了,因為您正在遍歷range(len(s))但尋址s[i+1] i指向s的最后一個索引時,這會導致一對一錯誤,因此i+1引發IndexError 解決此問題的一種方法是循環遍歷range(len(s)-1) ,但生成要迭代的內容更像是 Pythonic。

對於不是絕對巨大的字符串, zip(s, s[1:])不是性能問題,因此您可以執行以下操作:

counts = []
count = 1
for a, b in zip(s, s[1:]):
    if a==b:
        count += 1
    else:
        counts.append((a, count))
        count = 1

唯一的問題是,如果最后一個字符是唯一的,則必須對其進行特殊處理。 這可以通過itertools.zip_longest修復

import itertools

counts = []
count = 1
for a, b in itertools.zip_longest(s, s[1:], fillvalue=None):
    if a==b:
        count += 1
    else:
        counts.append((a, count))
        count = 1

如果您確實有一個非常大的字符串並且不能忍受一次將其中兩個保存在內存中,您可以使用itertools配方pairwise

def pairwise(iterable):
    """iterates pairwise without holding an extra copy of iterable in memory"""
    a, b = itertools.tee(iterable)
    next(b, None)
    return itertools.zip_longest(a, b, fillvalue=None)

counts = []
count = 1
for a, b in pairwise(s):
    ...

“那樣”的解決方案,只有基本的陳述:

word="100011010" #word = "1"
count=1
length=""
if len(word)>1:
    for i in range(1,len(word)):
       if word[i-1]==word[i]:
          count+=1
       else :
           length += word[i-1]+" repeats "+str(count)+", "
           count=1
    length += ("and "+word[i]+" repeats "+str(count))
else:
    i=0
    length += ("and "+word[i]+" repeats "+str(count))
print (length)

輸出 :

'1 repeats 1, 0 repeats 3, 1 repeats 2, 0 repeats 1, 1 repeats 1, and 0 repeats 1'
#'1 repeats 1'

總計(無子分組)

#!/usr/bin/python3 -B

charseq = 'abbcccdddd'
distros = { c:1 for c in charseq  }

for c in range(len(charseq)-1):
    if charseq[c] == charseq[c+1]:
        distros[charseq[c]] += 1

print(distros)

我將對有趣的線條進行簡要說明。

distros = { c:1 for c in charseq  }

上面這行是一個字典理解,它基本上遍歷charseq的字符,並為字典創建一個鍵/值對,其中鍵是字符,值是到目前為止遇到的次數。

然后是循環:

for c in range(len(charseq)-1):

我們從0length - 1以避免超出循環體中c+1索引的范圍。

if charseq[c] == charseq[c+1]:
    distros[charseq[c]] += 1

此時,我們知道的每個匹配項都是連續的,因此我們只需在字符鍵上加 1。 例如,如果我們拍攝一次迭代的快照,代碼可能如下所示(出於說明目的,使用直接值而不是變量):

# replacing vars for their values
if charseq[1] == charseq[1+1]:
    distros[charseq[1]] += 1

# this is a snapshot of a single comparison here and what happens later
if 'b' == 'b':
    distros['b'] += 1

您可以在下面看到帶有正確計數的程序輸出:

➜  /tmp  ./counter.py
{'b': 2, 'a': 1, 'c': 3, 'd': 4}

您只需將len(word)更改為len(word) - 1 也就是說,您還可以使用False的值為 0 且True的值為 1 的事實與sum

sum(word[i] == word[i+1] for i in range(len(word)-1))

這會產生(False, True, True, False)的總和,其中False為 0, True為 1 - 這就是您所追求的。

如果您希望這是安全的,您需要保護空詞(索引 -1 訪問):

sum(word[i] == word[i+1] for i in range(max(0, len(word)-1)))

這可以通過zip改進:

sum(c1 == c2 for c1, c2 in zip(word[:-1], word[1:]))

如果我們想在不循環的情況下計算連續字符,我們可以使用pandas

In [1]: import pandas as pd

In [2]: sample = 'abbcccddddaaaaffaaa'
In [3]: d = pd.Series(list(sample))

In [4]: [(cat[1], grp.shape[0]) for cat, grp in d.groupby([d.ne(d.shift()).cumsum(), d])]
Out[4]: [('a', 1), ('b', 2), ('c', 3), ('d', 4), ('a', 4), ('f', 2), ('a', 3)]

關鍵是找到之前值不同的第一個元素,然后在pandas進行適當的分組:

In [5]: sample = 'abba'
In [6]: d = pd.Series(list(sample))

In [7]: d.ne(d.shift())
Out[7]:
0     True
1     True
2    False
3     True
dtype: bool

In [8]: d.ne(d.shift()).cumsum()
Out[8]:
0    1
1    2
2    2
3    3
dtype: int32

這是我在 python 3 中查找二進制字符串中最大連續 1 數的簡單代碼:

count= 0
maxcount = 0
for i in str(bin(13)):
    if i == '1':
        count +=1
    elif count > maxcount:
        maxcount = count;
        count = 0
    else:
        count = 0
if count > maxcount: maxcount = count        
maxcount

獨特的方法: - 如果你只是在尋找計數連續1的使用Bit Magic:這個想法是基於這樣一個概念:如果我們和一個帶有自身移位版本的位序列,我們就會有效地從每一個中移除尾隨1連續1的序列。

  11101111   (x)
& 11011110   (x << 1)
----------
  11001110   (x & (x << 1)) 
    ^    ^
    |    |

尾隨1被移除所以操作x =(x&(x << 1))在x的二進制表示中將每個1s序列的長度減少1。 如果我們繼續在循環中執行此操作,我們最終得到x = 0.達到0所需的迭代次數實際上是最長連續序列1s的長度。

無需計數或分組。 只需注意發生變化的索引並減去連續的索引。

w = "111000222334455555"
iw = [0] + [i+1 for i in range(len(w)-1) if w[i] != w[i+1]] + [len(w)]
dw = [w[i] for i in range(len(w)-1) if w[i] != w[i+1]] + [w[-1]]
cw = [ iw[j] - iw[j-1] for j in range(1, len(iw) ) ]

print(dw)  # digits
['1', '0', '2', '3', '4']
print(cw)  # counts
[3, 3, 3, 2, 2, 5]

w = 'XXYXYYYXYXXzzzzzYYY'
iw = [0] + [i+1 for i in range(len(w)-1) if w[i] != w[i+1]] + [len(w)]
dw = [w[i] for i in range(len(w)-1) if w[i] != w[i+1]] + [w[-1]]
cw = [ iw[j] - iw[j-1] for j in range(1, len(iw) ) ]
print(dw)  # characters
print(cw)  # digits

['X', 'Y', 'X', 'Y', 'X', 'Y', 'X', 'z', 'Y']
[2, 1, 1, 3, 1, 1, 2, 5, 3]

一個單行,返回沒有導入的連續字符的數量:

def f(x):s=x+" ";t=[x[1] for x in zip(s[0:],s[1:],s[2:]) if (x[1]==x[0])or(x[1]==x[2])];return {h: t.count(h) for h in set(t)}

這將返回列表中任何重復字符在連續字符運行中的次數。

或者,這完成了同樣的事情,盡管速度要慢得多:

def A(m):t=[thing for x,thing in enumerate(m) if thing in [(m[x+1] if x+1<len(m) else None),(m[x-1] if x-1>0 else None)]];return {h: t.count(h) for h in set(t)}

在性能方面,我運行它們

site = 'https://web.njit.edu/~cm395/theBeeMovieScript/'
s = urllib.request.urlopen(site).read(100_000)
s = str(copy.deepcopy(s))
print(timeit.timeit('A(s)',globals=locals(),number=100))
print(timeit.timeit('f(s)',globals=locals(),number=100))

這導致:

12.528256356999918
5.351301653001428

這種方法肯定可以改進,但不使用任何外部庫,這是我能想到的最好的方法。

在蟒蛇中

your_string = "wwwwweaaaawwbbbbn"
current = ''
count = 0
for index, loop in enumerate(your_string):
    current = loop
    count = count + 1
    if index == len(your_string)-1:
        print(f"{count}{current}", end ='')
        break

    if your_string[index+1] != current:
        print(f"{count}{current}",end ='')
        count = 0
        continue

這將輸出

5w1e4a2w4b1n
#I wrote the code using simple loops and if statement
s='feeekksssh' #len(s) =11
count=1  #f:0, e:3, j:2, s:3 h:1
l=[]
for i in range(1,len(s)): #range(1,10)
    if s[i-1]==s[i]:
        count = count+1
    else:
        l.append(count)
        count=1
    if i == len(s)-1: #To check the last character sequence we need loop reverse order
        reverse_count=1
        for i in range(-1,-(len(s)),-1): #Lopping only for last character
            if s[i] == s[i-1]:
                reverse_count = reverse_count+1
            else:
                l.append(reverse_count)
                break
print(l)

今天面試,問了同樣的問題。 我一直在努力考慮最初的解決方案:

s = 'abbcccda'

old = ''
cnt = 0
res = ''
for c in s:
    cnt += 1
    if old != c:
        res += f'{old}{cnt}'
        old = c
        cnt = 0  # default 0 or 1 neither work
print(res)
#  1a1b2c3d1

可悲的是,這個解決方案總是得到意想不到的邊緣情況結果(有沒有人修復代碼?也許我需要發布另一個問題),最后讓面試超時。

面試結束后我冷靜了下來,很快就得到了我認為的穩定解決方案(雖然我最喜歡groupby )。

s = 'abbcccda'

olds = []
for c in s:
    if olds and c in olds[-1]:
        olds[-1].append(c)
    else:
        olds.append([c])
print(olds)
res = ''.join([f'{lst[0]}{len(lst)}' for lst in olds])
print(res)

#  [['a'], ['b', 'b'], ['c', 'c', 'c'], ['d'], ['a']]
#  a1b2c3d1a1

這是我的簡單解決方案:

def count_chars(s):
    size = len(s)
    count = 1
    op = ''
    for i in range(1, size):
        if s[i] == s[i-1]:
            count += 1
        else:
            op += "{}{}".format(count, s[i-1])
            count = 1
    if size:
        op += "{}{}".format(count, s[size-1])

    return op
data_input = 'aabaaaabbaaaaax'
start = 0
end = 0
temp_dict = dict()
while start < len(data_input):
  if data_input[start] == data_input[end]:
     end = end + 1
  if end == len(data_input):
     value = data_input[start:end]
     temp_dict[value] = len(value)
     break
  if data_input[start] != data_input[end]:
     value = data_input[start:end]
     temp_dict[value] = len(value)
     start = end
print(temp_dict)

問題:我們需要計算連續字符並返回字符及其計數。

def countWithString(input_string:str)-> str:
    count = 1
    output = ''
 
    for i in range(1,len(input_string)):
        if input_string[i]==input_string[i-1]:
            count +=1
        else:
            output += f"{count}{input_string[i-1]}"
            count = 1
    # Used to add last string count (at last else condition will not run and data will not be inserted to ouput string)
    output += f"{count}{input_string[-1]}"
    return output

countWithString(input)

input:'aaabbbaabbcc' output:'3a3b2a2b2c'

Time Complexity: O(n) Space Complexity: O(1)

temp_str = "aaaajjbbbeeeeewwjjj"
def consecutive_charcounter(input_str):
    counter = 0
    temp_list = []
    for i in range(len(input_str)):
        if i==0:
            counter+=1
        elif input_str[i]== input_str[i-1]:
            counter+=1
            if i == len(input_str)-1:
                temp_list.extend([input_str[i - 1], str(counter)])
        else:
            temp_list.extend([input_str[i-1],str(counter)])
            counter = 1
    print("".join(temp_list))

連續字符計數器(temp_str)

[enter image description here][1]

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM