This is called run-length encoding. Each run (the same character repeated next to itself) is written once, followed by how many times it repeats. A character that appears only once is written without a number.
The program
def compress(text): if text == "": return "" result = "" current = text[0] count = 1 for ch in text[1:]: if ch == current: count += 1 else: result += current + (str(count) if count > 1 else "") current = ch count = 1 # the last run has no different character after it, so add it here result += current + (str(count) if count > 1 else "") return result for word in ["aaabbbcc", "aabcccccaaa", "abc", "z", ""]: print(f"{word!r} -> {compress(word)!r}")
'aaabbbcc' -> 'a3b3c2' 'aabcccccaaa' -> 'a2bc5a3' 'abc' -> 'abc' 'z' -> 'z' '' -> ''
How it works
currentis the character of the run being counted, andcountis its length so far.- When the next character is different, the run is finished: add it to
resultand start a new run withcount = 1. - After the loop, the last run is still waiting, so it is added once more. Forgetting this line is the most common bug in this program.
- The empty string is checked at the start, because
text[0]would raise anIndexError.
Another way: itertools.groupby()
groupby() from the itertools module splits a string into runs for you. For each run it gives the character and the group of repeated characters:
from itertools import groupby def compress(text): result = "" for ch, group in groupby(text): count = len(list(group)) result += ch + (str(count) if count > 1 else "") return result print(compress("aabcccccaaa"))
a2bc5a3
Note that "aaa" at the end is a separate run from "aa" at the start. Runs are counted only when the same characters are next to each other.