将两个string转换为一个布尔值数组的快速方法是什么?
我有一个很长的string(有时超过1000个字符),我想转换为一个布尔值数组。 而且它需要非常快速地做很多次。
let input: String = "001" let output: [Bool] = [false, false, true]
我天真的尝试是这样的:
input.characters.map { $0 == "1" }
但是这比我想要的要慢很多。 我的分析表明, map
是经济放缓的地方,但我不知道我能做多less简单。
我觉得在没有Swift / ObjC的开销的情况下,这样做会很快。 在C中,我认为这是一个简单for
循环,其中一个字节的内存与一个常量进行比较,但我不知道我应该看什么函数或语法。
有没有办法做得更快?
更新:
我也试过了
output = [] for char in input.characters { output.append(char == "1") }
它快了大约15%。 我希望比这更多。
这是更快的:
// Algorithm 'A' let input = "0101010110010101010" var output = Array<Bool>(count: input.characters.count, repeatedValue: false) for (index, char) in input.characters.enumerate() where char == "1" { output[index] = true }
更新:在input = "010101011010101001000100000011010101010101010101"
0.0741 / 0.0087,这种方法比作者的8.46倍更快。 更大的数据相关性更积极。
此外,使用nulTerminatedUTF8
速度稍微增加,但并不总是速度高于algorithmA :
// Algorithm 'B' let input = "10101010101011111110101000010100101001010101" var output = Array<Bool>(count: input.nulTerminatedUTF8.count, repeatedValue: false) for (index, code) in input.nulTerminatedUTF8.enumerate() where code == 49 { output[index] = true }
在结果图中出现,input长度为2196 ,其中第一个和最后一个0..1,A – 秒,B – 第三个点。 A :0.311秒, B :0.304秒
import Foundation let input:String = "010101011001010101001010101100101010100101010110010101010101011001010101001010101100101010100101010101011001010101001010101100101010100101010" var start = clock() var output = Array<Bool>(count: input.nulTerminatedUTF8.count, repeatedValue: false) var index = 0 for val in input.nulTerminatedUTF8 { if val != 49 { output[index] = true } index+=1 } var diff = clock() - start; var msec = diff * 1000 / UInt(CLOCKS_PER_SEC); print("Time taken \(Double(msec)/1000.0) seconds \(msec%1000) milliseconds");
这应该是非常快的。 试试看。 对于010101011010101001000100000011010101010101010101
它需要0.039秒。
我想这是尽可能快的:
let targ = Character("1") let input: String = "001" // your real string goes here let inputchars = Array(input.characters) var output:[Bool] = Array.init(count: inputchars.count, repeatedValue: false) inputchars.withUnsafeBufferPointer { inputbuf in output.withUnsafeMutableBufferPointer { outputbuf in var ptr1 = inputbuf.baseAddress var ptr2 = outputbuf.baseAddress for _ in 0..<inputbuf.count { ptr2.memory = ptr1.memory == targ ptr1 = ptr1.successor() ptr2 = ptr2.successor() } } } // output now contains the result
原因在于,由于使用了缓冲区指针,我们只需循环访问连续的内存,就像循环访问C数组一样,通过增加其指针。 因此,一旦我们经过了最初的设置,这应该和C中一样快
编辑在实际testing中,OP的原始方法和这一个之间的时差是两者之间的差异
13.3660290241241
和
0.219357967376709
这是一个相当戏剧性的加速。 然而,我急于补充,我已经排除了时间testing的初始设置。 这一行:
let inputchars = Array(input.characters)
…特别贵。
这应该比enumerate() where char == "1"
快一点enumerate() where char == "1"
版本(对于500_000交替的0.557s和来自diampiax的1.159salgorithm'A'的零)
let input = inputStr.utf8 let n = input.count var output = [Bool](count: n, repeatedValue: false) let one = UInt8(49) // 1 for (idx, char) in input.enumerate() { if char == one { output[idx] = true } }
但是它的可读性也很差; -p
编辑: 两个版本都比地图变种慢,也许你忘了编译优化?
还有一步应该加快速度。 使用reserveCapacity
将在循环开始之前调整数组的大小,而不是在循环运行时尝试这样做。
var output = [Bool]() output.reserveCapacity(input.characters.count) for char in input.characters { output.append(char == "1") }
使用withCString(_:)
来检索一个原始的UnsafePointer<Int8>
。 迭代,比较49(ASCII值为"1"
)。
怎么样更实用的风格? 这不是最快的(47毫秒),今天肯定…
import Cocoa let start = clock() let bools = [Bool](([Character] ("010101011001010101001010101100101010100101010110010101010101011001010101001010101100101010100101010101011001010101001010101100101010100101010".characters)).map({$0 == "1"})) let msec = (clock() - start) * 1000 / UInt(CLOCKS_PER_SEC); print("Time taken \(Double(msec)/1000.0) seconds \(msec%1000) milliseconds");
我需要进行一些testing,但是我认为包括原始地图在内的许多方法的一个问题是,他们需要迭代string来计算字符数,然后第二次实际处理字符数。
你有没有尝试过:
let output = [Bool](input.characters.lazy.map { $0 == "1" })
这可能只能做一次迭代。
另一个可以加快速度的方法是避免使用string,而是使用适当编码的字符数组(特别是如果是更大的固定长度单位(如UTF16或ASCII),那么长度查找就是O(1)而不是O(n),迭代也可能更快
顺便说一句,在优化器启用的情况下总是testing性能,从来没有在游乐场中testing性能,因为性能特征是完全不同的,有时是100倍。
- 如何将底部边框添加到tableview部分标题
- 在一个可以略微离开屏幕的正在运行的animation中检索轻敲的UIButton
- 从不同的文件更新表视图 – 无法调用没有参数的“reloadData”
- UIDatePicker显示不正确
- Swift:尝试从我的应用程序中打开Safari浏览器中的URL时,获取“快照未呈现的视图”错误
- iOS – Firebasefilter查询
- 使用UIBezierPath:byRoundingCorners:使用Swift 2和Swift 3
- 无法将types'UInt'的值转换为期望的参数types'UnsafeMutablePointer <UInt>'
- 打印到标签(Swift 2)