ruby有函数string.squeeze,但我似乎无法找到一个快速的等价物。
例如我想打开簿记员 - > bokepr
我唯一的选择是创建一组字符,然后将字符集中的字符拉回字符串?
有更好的方法吗?
答案 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: ""))