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")]