【问题标题】:Gradually and randomly visualize string逐渐随机地可视化字符串
【发布时间】:2019-03-25 01:58:10
【问题描述】:

我目前正在开发一个简单的程序,以在两次迭代中逐渐随机地可视化一个字符串。现在我已经设法进行了第一次迭代,但我不确定如何进行第二次迭代。如果有人可以提供任何示例或建议,我将不胜感激。我的代码如下所示:

let s = "Hello playground"
let factor = 0.25
let factor2 = 0.45

var n = s.filter({ $0 != " " }).count  // # of non-space characters
var m = lrint(factor * Double(n))      // # of characters to display

let t = String(s.map { c -> Character in
        if c == " " {
        // Preserve space
        return " "
    } else if Int.random(in: 0..<n) < m {
        // Replace
        m -= 1
        n -= 1
        return c
    } else {
        // Keep
        n -= 1
        return "_"
    }
})

print(t)  // h_l__ _l_______d

为了澄清,我想在第二次迭代中使用 factor2 来打印在 t 顶部随机添加字母的东西,看起来像这样 h_l_o pl_g_____d。

【问题讨论】:

标签: ios swift iteration


【解决方案1】:

替换字符

@MartinR 的代码开始,您应该记住已被替换的索引。因此,我将稍微更改替换字符的代码:

let s = "Hello playground"
let factor = 0.25
let factor2 = 0.45

var n = s.filter({ $0 != " " }).count  // # of non-space characters
let nonSpaces = n
var m = lrint(factor * Double(n))      // # of characters to display

var indices = Array(s.indices)

var t = ""

for i in s.indices {
    let c = s[i]
    if c == " " {
        // Preserve space
        t.append(" ")
        indices.removeAll(where: { $0 == i })
    } else if Int.random(in: 0..<n) < m {
        // Keep
        m -= 1
        n -= 1
        t.append(c)
        indices.removeAll(where: { $0 == i })
    } else {
        // Replace
        n -= 1
        t.append("_")
    }
}

print(t)   //For example: _e___ ______ou_d

揭示人物

为此,我们应该计算要显示的字符数:

m = lrint((factor2 - factor) * Double(nonSpaces))

为了随机选择三个索引来显示,我们将indices 洗牌,然后替换m 第一个索引:

indices.shuffle()
var u = t
for i in 0..<m {
    let index = indices[i]
    u.replaceSubrange(index..<u.index(after: index), with: String(s[index]))
}
indices.removeSubrange(0..<m)

print(u)   //For example: _e__o _l__g_ou_d

【讨论】:

    【解决方案2】:

    我写了StringRevealer struct,它为你处理所有揭示逻辑:

    /// Hide all unicode letter characters as `_` symbol.
    struct StringRevealer {
    
        /// We need mapping between index of string character and his position in state array.
        /// This struct represent one such record
        private struct Symbol: Hashable {
            let index: String.Index
            let position: Int
        }
    
        private let originalString: String
        private var currentState: [Character]
        private let charactersCount: Int
        private var revealed: Int
        var revealedPercent: Double {
            return Double(revealed) / Double(charactersCount)
        }
        private var unrevealedSymbols: Set<Symbol>
    
        init(_ text: String) {
            originalString = text
            var state: [Character] = []
            var symbols: [Symbol] = []
            var count = 0
            var index = originalString.startIndex
            var i = 0
            while index != originalString.endIndex {
                let char = originalString[index]
                if CharacterSet.letters.contains(char.unicodeScalars.first!) {
                    state.append("_")
                    symbols.append(Symbol(index: index, position: i))
                    count += 1
                } else {
                    state.append(char)
                }
                index = originalString.index(after: index)
                i += 1
            }
            currentState = state
            charactersCount = count
            revealed = 0
            unrevealedSymbols = Set(symbols)
        }
    
        /// Current state of text. O(n) conplexity
        func text() -> String {
            return currentState.reduce(into: "") { $0.append($1) }
        }
    
        /// Reveal one random symbol in string
        mutating func reveal() {
            guard let symbol = unrevealedSymbols.randomElement() else { return }
            unrevealedSymbols.remove(symbol)
            currentState[symbol.position] = originalString[symbol.index]
            revealed += 1
        }
    
        /// Reveal random symbols on string until `revealedPercent` > `percent`
        mutating func reveal(until percent: Double) {
            guard percent <= 1 else { return }
            while revealedPercent < percent {
                reveal()
            }
        }
    }
    
    var revealer = StringRevealer("Hello товарищ! ?")
    print(revealer.text())
    print(revealer.revealedPercent)
    for percent in [0.25, 0.45, 0.8] {
        revealer.reveal(until: percent)
        print(revealer.text())
        print(revealer.revealedPercent)
    }
    

    它在内部使用CharacterSet.letters,因此应该支持大多数语言,忽略表情符号和非字母字符。

    【讨论】:

      猜你喜欢
      • 2018-11-26
      • 1970-01-01
      • 2015-09-07
      • 1970-01-01
      • 2016-01-04
      • 1970-01-01
      • 1970-01-01
      • 2019-08-07
      • 2014-10-21
      相关资源
      最近更新 更多