如何从Swift中的字符串中删除重复的字符

时间:2017-05-10 21:35:36

标签: swift string

ruby​​有函数string.squeeze,但我似乎无法找到一个快速的等价物。

例如我想打开簿记员 - > bokepr

我唯一的选择是创建一组字符,然后将字符集中的字符拉回字符串?

有更好的方法吗?

5 个答案:

答案 0 :(得分:6)

修改/更新: Swift 4.2或更高版本

您可以使用集合来过滤重复的字符:

let str = "bookkeeper"
var set = Set<Character>()
let squeezed = str.filter{ set.insert($0).inserted } 

print(squeezed)   //  "bokepr"

或者作为RangeReplaceableCollection的扩展,它也将扩展String和Substrings:

extension RangeReplaceableCollection where Element: Hashable {
    var squeezed: Self {
        var set = Set<Element>()
        return filter{ set.insert($0).inserted }
    }
}
let str = "bookkeeper"
print(str.squeezed)      //  "bokepr"
print(str[...].squeezed) //  "bokepr"

答案 1 :(得分:1)

我会使用another answer of mine中的这段代码,它会删除序列的所有重复项(仅保留每个序列的第一个匹配项),同时保持顺序。

extension Sequence where Iterator.Element: Hashable {
    func unique() -> [Iterator.Element] {
        var alreadyAdded = Set<Iterator.Element>()
        return self.filter { alreadyAdded.insert($0).inserted }
    }
}

然后我会用一些逻辑将它包装成一个序列(通过获取它的characters),unqiue's,然后将结果恢复为字符串:

extension String {
    func uniqueCharacters() -> String {
        return String(self.characters.unique())
    }
}

print("bookkeeper".uniqueCharacters()) // => "bokepr"

答案 2 :(得分:0)

这是我在网上找到的解决方案,但我不认为它是最佳的。

    func removeDuplicateLetters(_ s: String) -> String {
    if s.characters.count == 0 {
        return ""
    }

    let aNum = Int("a".unicodeScalars.filter{$0.isASCII}.map{$0.value}.first!)
    let characters = Array(s.lowercased().characters)
    var counts = [Int](repeatElement(0, count: 26))
    var visited = [Bool](repeatElement(false, count: 26))
    var stack = [Character]()
    var i = 0

    for character in characters {
        if let num = asciiValueOfCharacter(character) {
            counts[num - aNum] += 1
        }
    }

    for character in characters {
        if let num = asciiValueOfCharacter(character) {
            i = num - aNum
            counts[i] -= 1
            if visited[i] {
                continue
            }
            while !stack.isEmpty, let peekNum = asciiValueOfCharacter(stack.last!), num < peekNum && counts[peekNum - aNum] != 0 {
                visited[peekNum - aNum] = false
                stack.removeLast()
            }
            stack.append(character)
            visited[i] = true
        }
    }

    return String(stack)
}

func asciiValueOfCharacter(_ character: Character) -> Int? {
    let value = String(character).unicodeScalars.filter{$0.isASCII}.first?.value ?? 0
    return Int(value)
}

答案 3 :(得分:0)

以下是使用reduce(),

执行此操作的一种方法
let newChar = str.characters.reduce("") { partial, char in
  guard let _ = partial.range(of: String(char)) else {
    return partial.appending(String(char))
  }
  return partial
}

正如Leo所建议的,这是相同方法的一个较短版本,

let newChar = str.characters.reduce("") { $0.range(of: String($1)) == nil ? $0.appending(String($1)) : $0 }

答案 4 :(得分:0)

另一种解决方案

let str = "Bookeeper"
let newChar = str.reduce("" , {
    if $0.contains($1) {
        return "\($0)"
    } else {
      return "\($0)\($1)"
    }
})

print(str.replacingOccurrences(of: " ", with: ""))