我有一个长字符串(有时超过1000个字符),我想将其转换为布尔值数组。它需要很快地完成这项工作。
let input: String = "001"
let output: [Bool] = [false, false, true]
我天真的尝试是这样的:
input.characters.map { $0 == "1" }
但这比我想要的要慢很多。我的分析告诉我map
是减速的地方,但我不确定我能做到多么简单。
我觉得如果没有Swift&ObjC的开销,这将会很快。在C中,我认为这是一个简单的for
循环,其中一个字节的内存与一个常量进行比较,但我不确定我应该看到的函数或语法是什么。
有没有办法更快地完成这项工作?
更新
我也试过了
output = []
for char in input.characters {
output.append(char == "1")
}
它的速度提高了约15%。我希望能有更多的东西。
答案 0 :(得分:12)
这更快:
// 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
速度稍微提高一点,但速度并不总是高于算法 A :
// 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
}
在结果图中出现,输入长度 2196 ,其中第一个和最后一个0..1,A - 秒,B - 第三个点。 A :0.311秒, B :0.304秒
答案 1 :(得分:5)
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秒。
答案 2 :(得分:1)
这应该比[[255 255 255 106 214 113 73 224 83 164 68 195]
[255 255 255 130 99 75 35 158 126 153 133 135]
[255 255 255 152 79 15 7 101 175 68 45 71]
[106 254 55 97 238 15 85 243 81 249 77 86]]
[[255 255 255 106 214 113 73 224 83 164 68 195]
[255 255 255 130 99 75 35 158 126 153 133 135]
[255 255 255 152 79 15 7 101 175 68 45 71]
[106 254 55 97 238 15 85 243 81 249 77 86]]
Round-trip result: the arrays are equal.
版本快一点(对于500_000个交替的0和0而言为0.557s而对于来自diampiax的1.159s算法'A')
enumerate() where char == "1"
但它的可读性也差得多;-p
编辑: 两个版本都比地图版本慢,可能你忘了用优化编译?
答案 3 :(得分:1)
我猜这是尽可能快的:
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中一样快。
编辑在实际测试中,OP原始方法与此方法之间的时差是
之间的差异13.3660290241241
和
0.219357967376709
这是一个相当戏剧性的加速。但是,我赶紧补充说,我已经排除时间测试的初始设置。这一行:
let inputchars = Array(input.characters)
......特别贵。
答案 4 :(得分:0)
还有一步应该加快速度。使用new_dataframe = df['A'].to_frame()
new_dataframe.head()
from pyspark.sql import SQLContext
spDF = sqlContext.createDataFrame(new_dataframe)
spDF.show()
将在循环开始之前调整一次数组的大小,而不是在循环运行时尝试执行此操作。
reserveCapacity
答案 5 :(得分:0)
使用withCString(_:)
检索原始UnsafePointer<Int8>
。迭代并比较49("1"
的ascii值)。
答案 6 :(得分:0)
更实用的风格怎么样?它不是最快的(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");
答案 7 :(得分:0)
我需要进行一些测试以确定,但我认为包括原始地图在内的许多方法存在的一个问题是,他们需要迭代字符串来计算字符数,然后第二次实际处理字符。
你试过了吗?
let output = [Bool](input.characters.lazy.map { $0 == "1" })
这可能只进行一次迭代。
另一件可以加快速度的事情是,如果你可以避免使用字符串,而是使用适当编码的字符数组(特别是如果是更固定大小的单位(例如UTF16或ASCII)。那么长度查找将是O (1)而不是O(n),迭代也可能更快
BTW始终在启用优化器的情况下测试性能,从不在Playground中测试性能,因为性能特征完全不同,有时是100倍。