RLE ALgorithm in python

1.1k Views Asked by At

like the title suggest I want to do an RLE algorithm and I have few problems with that

for example in RLE algorithm if we take aaaabbbccd it should return a4b3c2d1 as a result

the rle function should return the compressed string of aaabbbccccddddd

rle(data : str) : str

so it would be a3b3c4d5

Here's the code I know it's wrong but I don't know If it was a good way to begin

def rle(data):
            
    data = 'aaabbbccccddddd'    
    for i in range(0,len(data)):
                                  
        if data.count(f'{i}') > 1:
           
           data.replace(i, data.count(f'{i}'))
           print(data)

print(rle(data))
2

There are 2 best solutions below

0
On

This should work better

def rle(data):
    # Initialize a few variables
    prev = None
    cnt = 0 
    res = ""
    for i in data:
        if i == prev:
           # if same char as previous one, just add one to counter
           cnt += 1
        else:
           # Check that we are not at first round and add to result
           if prev != None:
              res += "%s%s" % (cnt,prev)
           # Set new character as previous one
           prev = i
    # Add last char to result
    res += "%s%s" % (cnt,prev)
    return res
           
      
                                
print(rle("aaabbbccccddddd"))

0
On
data = 'aaabbbccccddddd'
seq = []
r = None
for d in data:
    if d != r:
        seq.append(d)
        seq.append(str(1))
        r = d
    else:
        seq[-1] = str(int(seq[-1]) + 1)
print("".join(seq))

I thought that this code snippet is simple, and so didn't explain it...

we have a str and want to convert it to Char-TheNumberOfRepetitions pairs, like ['a',3,'b',3,'c',4,...], so we loop a char over str and when it is new, we add [char, 1] to list, otherwise, we add 1 to last element of list while we get a new char...

r variable is for new char recognition and is a temp variable that we store every new char (if a char was not equal to it, replace)

finally, we convert ['a',3,'b',3,'c',4,...] to str, using join

why we use str() and int()? because python join method is a bit silly :) and throw an exception, if an element of list be int... and everytime we convert it to int to add 1 and then convert to str, again...

why not map? because I assume that OP is beginner and map is complicate for him...

and, a more pythonic way:

def rle(data: str) -> str:
    
    seq = [data[0], 1]

    for elem in data[1:]:
        if elem != seq[-2]: 
            seq += [elem, 1]
        else:
            seq[-1] += 1
    
    return ''.join(map(str, seq))

and reverse:

def reverse_rle(data: str, end_char = '$') -> str:
    
    def convert(): return seq[:-2] + [seq[-2] * (seq[-1] or 1)]

    seq = [data[0], 0]

    for elem in data[1:] + end_char:
        if elem.isdigit():
            seq[-1] = seq[-1] * 10 + int(elem)
        else:
            seq = convert()
            if elem != end_char:
                seq += [elem, 0]
    
    return "".join(seq)

and if you dont want to use end_char:

def reverse_rle(data: str) -> str:
    
    def convert(): return seq[:-2] + [seq[-2] * (seq[-1] or 1)]

    seq = [data[0], 0]

    for elem in data[1:]:
        if elem.isdigit():
            seq[-1] = seq[-1] * 10 + int(elem)
        else:
            seq = convert() + [elem, 0]
    
    return "".join(convert())