在 Swift 中有更容易阅读的 运行-length 编码吗?

Any easier to read run-length Encoding in Swift?

任何人都可以在 swift 中编写 运行-length 编码代码,比下面的代码更容易阅读,或者至少解释一下我从 rosettecode.org 得到的代码吗? 这是输入&输出和代码

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

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

希望这能让你更容易理解。

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
}

如果你改用 reduce(into:) 会更容易理解:

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 [=10=].last?.1 ==  {
            // increase the first element of the last tuple tuple of the result
            [=10=][[=10=].index(before: [=10=].endIndex)].0 += 1 
        } else {
            // otherwise add a new tuple with a value of 1 and the current element (character) to the result
            [=10=] += CollectionOfOne((1, ))
        }
    }
}

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

您还可以扩展 Collection 并实现一个泛型 method/property

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

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

我用下面的方法解决了这个任务,可能有人更清楚:

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
}