簡體   English   中英

Python中的運行長度編碼

[英]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.

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