'Any easier to read run-length Encoding in Swift?

Can anyone write run-length encoding code in swift that is easier to read than the one below or at least explains the one i got from rosettecode.org ? Here is the input& output and the code

// "WWWBWW" -> [(3, W), (1, B), (2, W)]

func encode(input: String) -> [(Int, Character)] {
    return input.characters.reduce([(Int, Character)]()) {
        if $0.last?.1 == $1 { var r = $0; r[r.count - 1].0++; return r }
        return $0 + [(1, $1)]
    }
}


Solution 1:[1]

It would be easier to understand if you use reduce(into:) instead:

func encode(input: String) -> [(Int, Character)] {
    input.reduce(into: [(Int, Character)]()) {
        // if the second element of the last tuple of the result is equal to the current element (character) of the collection
        if $0.last?.1 == $1 {
            // increase the first element of the last tuple tuple of the result
            $0[$0.index(before: $0.endIndex)].0 += 1 
        } else {
            // otherwise add a new tuple with a value of 1 and the current element (character) to the result
            $0 += CollectionOfOne((1, $1))
        }
    }
}

encode(input: "WWWBWW")  // [(.0 3, .1 "W"), (.0 1, .1 "B"), (.0 2, .1 "W")]

You can also extend Collection and implement a generic method/property

extension Collection where Element: Equatable {
    var groupped: [(Int, Element)] {
        reduce(into: []) {
            if $0.last?.1 == $1 {
                $0[$0.index(before: $0.endIndex)].0 += 1
            } else {
                $0 += CollectionOfOne((1, $1))
            }
        }
    }
}

"WWWBWW".groupped    // [(.0 3, .1 "W"), (.0 1, .1 "B"), (.0 2, .1 "W")]

Solution 2:[2]

Hope this make it easier for you to understand.

func encode2(input: String) -> [(Int, Character)] {
    var result = [(Int, Character)]()

    input.forEach { char in
        if result.last?.1 == char {
            result[result.count - 1].0 += 1
        } else {
            result.append((1, char))
        }
    }
    
    return result
}

Solution 3:[3]

I've solved the task with the following way, which may be more clear for someone:

func compress(input: String) -> [(Int, Character)] {
    var output = [(Int, Character)]()
    var count: Int = 1 // count of repeated characters

    var i = 0

    while i < input.count { // select the current character

        var j = i + 1
        while j < input.count &&
                input[input.index(input.startIndex, offsetBy: i)] == input[input.index(input.startIndex, offsetBy: j)] { // count repeated charactes followed the current one
            count += 1
            j += 1
        }

        output.append((count, input[input.index(input.startIndex, offsetBy: i)]))

        i = j // move index for the current character to the index of the last repeated one
        count = 1 // reset count
    }

    return output
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Leo Dabus
Solution 2 congnd
Solution 3 Yulia