You can use reduce(into:_) to do so:
The logic is to keep an array (ie ordered), with letter, and its number of following occurence.
You iterate over the String, and check last entry. Increment its value, or append it to the array.
Then, you iterate over the reduce output, and create the final string.
func compressing(str: String) -> String {
let reduced = str.reduce(into: [(Character, Int)]()) { result, current in
guard var last = result.last else {
result.append((current, 1))
return
}
if last.0 == current {
last = (current, last.1 + 1)
result[result.count - 1] = last
} else {
result.append((current, 1))
}
}
print(reduced)
let output = reduced.map { String($0.0) + "\($0.1)" }.joined()
if output.count > str.count {
return str
} else {
return output
}
}
To test it:
let values: [(String, String)] = [("aaaaabbbbbbbbcd", "a5b8c1d1"),
("abcaaaaaaaaaaaaaaaaaabbc", "a1b1c1a18b2c1"),
("a111", "a113"),
("aaaaaaaaaaaaa", "a13")]
values.forEach {
let result = compressing(str: $0.0)
print("\(result) \(result == $0.1 ? "=" : "!")= \($0.1)")
}
Output:
[("a", 5), ("b", 8), ("c", 1), ("d", 1)]
a5b8c1d1 == a5b8c1d1
[("a", 1), ("b", 1), ("c", 1), ("a", 18), ("b", 2), ("c", 1)]
a1b1c1a18b2c1 == a1b1c1a18b2c1
[("a", 1), ("1", 3)]
a113 == a113
[("a", 13)]
a13 == a13
reduce(into:_)too to do so.