[英]Run length encoding in Python
我正在嘗試編寫一個簡單的 python 算法來解決這個問題。 你能幫我弄清楚為什么我的代碼不起作用:
問題:
如果任何字符重復超過 4 次,則整個重復字符集應替換為斜杠“/”,后跟一個 2 位數字,即該重復字符的長度,以及該字符。 例如,“aaaaa”將被編碼為“/05a”。 不應替換 4 個或更少字符的運行,因為執行編碼不會減少字符串的長度。
我的代碼:
def runLengthEncode (plainText):
res=''
a=''
for i in plainText:
if a.count(i)>0:
a+=i
else:
if len(a)>4:
res+="/" + str(len(a)) + a[0][:1]
else:
res+=a
a=i
return(res)
我在這里看到了許多很棒的解決方案,但沒有一個讓我覺得非常pythonic。 所以我正在為我今天為這個問題編寫的一個實現做出貢獻。
def run_length_encode(data: str) -> Iterator[Tuple[str, int]]:
"""Returns run length encoded Tuples for string"""
# A memory efficient (lazy) and pythonic solution using generators
return ((x, sum(1 for _ in y)) for x, y in groupby(data))
這將返回一個帶有字符和實例數的元組生成器,但也可以很容易地修改為返回一個字符串。 這樣做的一個好處是,如果您不需要用盡整個搜索空間,那么它都是惰性計算的,並且不會消耗比所需更多的內存或 cpu。
如果您仍然想要字符串編碼,可以很容易地為該用例修改代碼,如下所示:
def run_length_encode(data: str) -> str:
"""Returns run length encoded string for data"""
# A memory efficient (lazy) and pythonic solution using generators
return "".join(f"{x}{sum(1 for _ in y)}" for x, y in groupby(data))
這是適用於所有長度的更通用的運行長度編碼,而不僅僅是超過 4 個字符的編碼。 但是,如果需要,這也可以很容易地通過字符串的條件進行調整。
除了在編碼序列后設置a=i
並在打印到字符串中時為 int 設置寬度。 您還可以執行以下操作,以利用groupby
。 在構造字符串時使用format
也是一個好主意。
from itertools import groupby
def runLengthEncode (plainText):
res = []
for k,i in groupby(plainText):
run = list(i)
if(len(run) > 4):
res.append("/{:02}{}".format(len(run), k))
else:
res.extend(run)
return "".join(res)
Rosetta Code 有很多實現,應該很容易適應您的用例。
這是帶有正則表達式的 Python 代碼:
from re import sub
def encode(text):
'''
Doctest:
>>> encode('WWWWWWWWWWWWBWWWWWWWWWWWWBBBWWWWWWWWWWWWWWWWWWWWWWWWBWWWWWWWWWWWWWW')
'12W1B12W3B24W1B14W'
'''
return sub(r'(.)\1*', lambda m: str(len(m.group(0))) + m.group(1),
text)
def decode(text):
'''
Doctest:
>>> decode('12W1B12W3B24W1B14W')
'WWWWWWWWWWWWBWWWWWWWWWWWWBBBWWWWWWWWWWWWWWWWWWWWWWWWBWWWWWWWWWWWWWW'
'''
return sub(r'(\d+)(\D)', lambda m: m.group(2) * int(m.group(1)),
text)
textin = "WWWWWWWWWWWWBWWWWWWWWWWWWBBBWWWWWWWWWWWWWWWWWWWWWWWWBWWWWWWWWWWWWWW"
assert decode(encode(textin)) == textin
只需觀察行為:
>>> runLengthEncode("abcd")
'abc'
最后一個字符被忽略。 您必須附加您收集的內容。
>>> runLengthEncode("abbbbbcd")
'a/5b/5b'
哎呀,編碼后的問題。 即使找到足夠長的序列,也應該設置a=i
。
您可以將groupby()函數與列表/生成器理解結合使用:
from itertools import groupby, imap
''.join(x if reps <= 4 else "/%02d%s" % (reps, x) for x, reps in imap(lambda x: (x[0], len(list(x[1]))), groupby(s)))
Split=(list(input("Enter string: ")))
Split.append("")
a = 0
for i in range(len(Split)):
try:
if (Split[i] in Split) >0:
a = a + 1
if Split[i] != Split[i+1]:
print(Split[i],a)
a = 0
except IndexError:
print()
這更容易並且每次都有效
def RLE_comp_encode(text):
if text == text[0]*len(text) :
return str(len(text))+text[0]
else:
comp_text , r = '' , 1
for i in range (1,len(text)):
if text[i]==text[i-1]:
r +=1
if i == len(text)-1:
comp_text += str(r)+text[i]
else :
comp_text += str(r)+text[i-1]
r = 1
return comp_text
這對我有用,
我知道這不是最有效的解決方案,但我們還沒有研究過groupby()
類的函數,所以這是我所做的:
def runLengthEncode (plainText):
res=''
a=''
count = 0
for i in plainText:
count+=1
if a.count(i)>0:
a+=i
else:
if len(a)>4:
if len(a)<10:
res+="/0"+str(len(a))+a[0][:1]
else:
res+="/" + str(len(a)) + a[0][:1]
a=i
else:
res+=a
a=i
if count == len(plainText):
if len(a)>4:
if len(a)<10:
res+="/0"+str(len(a))+a[0][:1]
else:
res+="/" + str(len(a)) + a[0][:1]
else:
res+=a
return(res)
text=input("Please enter the string to encode")
encoded=[]
index=0
amount=1
while index<=(len(text)-1):
if index==(len(text)-1) or text[index]!=text[(index+1)]:
encoded.append((text[index],amount))
amount=1
else:
amount=amount+1
index=index+1
print(encoded)
我能想到的游程編碼的簡單解決方案:
對像"a4b5c6d7..."
這樣的字符串進行編碼:
def encode(s):
counts = {}
for c in s:
if counts.get(c) is None:
counts[c] = s.count(c)
return "".join(k+str(v) for k,v in counts.items())
解碼像"aaaaaabbbdddddccccc...."
這樣的字符串:
def decode(s):
return "".join((map(lambda tup: tup[0] * int(tup[1]), zip(s[0:len(s):2], s[1:len(s):2]))))
相當容易閱讀和簡單。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.