我正在尝试使用十六进制字符串并在每个其他字符之间插入破折号(例如" b201a968"到" b2-01-a9-68")。我找到了几种方法,但问题是我的字符串相当大(8066个字符),而且我能让它工作的速度最快,它还需要几秒钟。这些是我尝试过的方式以及他们花了多长时间。任何人都可以帮我优化这个功能吗?
//42.68 seconds
func reformatDebugString(string: String) -> String
{
var myString = string
var index = 2
while(true){
myString.insert("-", at: myString.index(myString.startIndex, offsetBy: index))
index += 3
if(index >= myString.characters.count){
break
}
}
return myString
}
//21.65 seconds
func reformatDebugString3(string: String) -> String
{
var myString = ""
let length = string.characters.count
var first = true
for i in 0...length-1{
let index = string.index(myString.startIndex, offsetBy: i)
let c = string[index]
myString += "\(c)"
if(!first){
myString += "-"
}
first = !first
}
return myString
}
//11.37 seconds
func reformatDebugString(string: String) -> String
{
var myString = string
var index = myString.characters.count - 2
while(true){
myString.insert("-", at: myString.index(myString.startIndex, offsetBy: index))
index -= 2
if(index == 0){
break
}
}
return myString
}
答案 0 :(得分:7)
所有这三种方法的问题是使用index(_:offsetBy:)
来获取循环中当前字符的索引。这是一个O(n)运算,其中n是偏移的距离 - 因此使所有三个函数都以二次方运行。
此外,对于解决方案#1和#3,插入到结果字符串中的操作是O(n)操作,因为插入点之后的所有字符都必须向上移动以容纳添加的字符。在这种情况下,从头开始构建字符串通常更便宜,因为我们可以在字符串的末尾添加一个给定的字符,如果字符串有足够的容量,则为O(1),O(n)否则。
同样对于解决方案#1,说myString.characters.count
是一个O(n)操作,所以不是你想在循环的每次迭代中做的事情。
因此,我们希望从头开始构建字符串,并避免索引和计算循环内的字符数。这是实现这一目标的一种方式:
extension String {
func addingDashes() -> String {
var result = ""
for (offset, character) in characters.enumerated() {
// don't insert a '-' before the first character,
// otherwise insert one before every other character.
if offset != 0 && offset % 2 == 0 {
result.append("-")
}
result.append(character)
}
return result
}
}
// ...
print("b201a968".addingDashes()) // b2-01-a9-68
发布版本中的最佳解决方案(#3)在我的计算机上耗时37.79秒,上述方法耗时0.023秒。
答案 1 :(得分:2)
正如Hamish的回答中所提到的,你应该避免这两件事:
string.index(string.startIndex, offsetBy: ...)
insert(_:at:)
所以,这可能是另一种方式:
func reformatDebugString4(string: String) -> String {
var result = ""
var currentIndex = string.startIndex
while currentIndex < string.endIndex {
let nextIndex = string.index(currentIndex, offsetBy: 2, limitedBy: string.endIndex) ?? string.endIndex
if currentIndex != string.startIndex {
result += "-"
}
result += string[currentIndex..<nextIndex]
currentIndex = nextIndex
}
return result
}