这是两个非常相似的地方Levenshtein Distance algorithms
。
Swift
实施:https :
//gist.github.com/bgreenlee/52d93a1d8fa1b8c1f38b
和Objective-C
实现:https :
//gist.github.com/boratlibre/1593632
在swift
一个是慢得多然后ObjC
实现我送给几个小时,使其速度更快,但......好像Swift
阵列和Strings
操作是不一样快objC
。
在2000年的random Strings
计算中,Swift
执行速度比慢约100(!!!)倍ObjC
。
老实说,我不知道可能出什么问题了,因为这很快
func levenshtein(aStr: String, bStr: String) -> Int {
// create character arrays
let a = Array(aStr)
let b = Array(bStr)
...
比整个算法慢几倍 Objective C
有谁知道如何加快swift
计算速度?
先感谢您!
附加
毕竟,建议的改进是快速代码,如下所示。在发行版配置中,它 比ObjC慢4倍 。
import Foundation
class Array2D {
var cols:Int, rows:Int
var matrix:UnsafeMutablePointer<Int>
init(cols:Int, rows:Int) {
self.cols = cols
self.rows = rows
matrix = UnsafeMutablePointer<Int>(malloc(UInt(cols * rows) * UInt(sizeof(Int))))
for i in 0...cols*rows {
matrix[i] = 0
}
}
subscript(col:Int, row:Int) -> Int {
get {
return matrix[cols * row + col] as Int
}
set {
matrix[cols*row+col] = newValue
}
}
func colCount() -> Int {
return self.cols
}
func rowCount() -> Int {
return self.rows
}
}
extension String {
func levenshteinDistanceFromStringSwift(comparingString: NSString) -> Int {
let aStr = self
let bStr = comparingString
// let a = Array(aStr.unicodeScalars)
// let b = Array(bStr.unicodeScalars)
let a:NSString = aStr
let b:NSString = bStr
var dist = Array2D(cols: a.length + 1, rows: b.length + 1)
for i in 1...a.length {
dist[i, 0] = i
}
for j in 1...b.length {
dist[0, j] = j
}
for i in 1...a.length {
for j in 1...b.length {
if a.characterAtIndex(i-1) == b.characterAtIndex(j-1) {
dist[i, j] = dist[i-1, j-1] // noop
} else {
dist[i, j] = min(
dist[i-1, j] + 1, // deletion
dist[i, j-1] + 1, // insertion
dist[i-1, j-1] + 1 // substitution
)
}
}
}
return dist[a.length, b.length]
}
func levenshteinDistanceFromStringObjC(comparingString: String) -> Int {
let aStr = self
let bStr = comparingString
//It is really strange, but I should link Objective-C coz dramatic slow swift performance
return aStr.compareWithWord(bStr, matchGain: 0, missingCost: 1)
}
}
malloc ?? NSString ?? 并在最后四倍速度下降?有人需要迅速了吗?
Swift代码比Objective-C代码慢的原因有很多。通过比较两个固定字符串100次,我制作了一个非常简单的测试用例。
第一个原因是Swift
Character
代表一个“扩展的字素簇”,其中可以包含多个Unicode代码点(例如“标志”)。这会使字符串分解为字符变慢。另一方面,Objective-C
NSString
将字符串存储为一系列UTF-16代码点。
如果您更换
let a = Array(aStr)
let b = Array(bStr)
通过
let a = Array(aStr.utf16)
let b = Array(bStr.utf16)
这样Swift代码也可以在UTF-16序列上运行,那么时间就减少到1.88秒。
二维数组的分配也很慢。分配单个一维数组更快。我在Array2D
这里找到了一个简单的类:http : //blog.trolieb.com/trouble-multiDimension-
arrays-swift/
class Array2D {
var cols:Int, rows:Int
var matrix: [Int]
init(cols:Int, rows:Int) {
self.cols = cols
self.rows = rows
matrix = Array(count:cols*rows, repeatedValue:0)
}
subscript(col:Int, row:Int) -> Int {
get {
return matrix[cols * row + col]
}
set {
matrix[cols*row+col] = newValue
}
}
func colCount() -> Int {
return self.cols
}
func rowCount() -> Int {
return self.rows
}
}
在代码中使用该类
func levenshtein(aStr: String, bStr: String) -> Int {
let a = Array(aStr.utf16)
let b = Array(bStr.utf16)
var dist = Array2D(cols: a.count + 1, rows: b.count + 1)
for i in 1...a.count {
dist[i, 0] = i
}
for j in 1...b.count {
dist[0, j] = j
}
for i in 1...a.count {
for j in 1...b.count {
if a[i-1] == b[j-1] {
dist[i, j] = dist[i-1, j-1] // noop
} else {
dist[i, j] = min(
dist[i-1, j] + 1, // deletion
dist[i, j-1] + 1, // insertion
dist[i-1, j-1] + 1 // substitution
)
}
}
}
return dist[a.count, b.count]
}
测试用例中的时间减少到0.84秒。
我在Swift代码中发现的最后一个瓶颈是min()
函数。Swift库具有一个min()
更快的内置函数。因此,只需从Swift代码中删除自定义函数,就可以将测试用例的时间减少到0.04秒,几乎与Objective-
C版本一样。
附录: 使用Unicode标量似乎更快一些:
let a = Array(aStr.unicodeScalars)
let b = Array(bStr.unicodeScalars)
并具有可以与代理对(例如表情符号)一起正常使用的优点。
字符串 字符串是shell编程中最常用最有用的数据类型(除了数字和字符串,也没啥其它类型好用了),字符串可以用单引号,也可以用双引号,也可以不用引号。单双引号的区别跟PHP类似: 单双引号的区别: 双引号里可以有变量,单引号则原样输出; 双引号里可以出现转义字符,单引号则原样输出; 单引号字串中不能出现单引号。 拼接字符串 #!/bin/bash str1='i' str2='love' str3
问题内容: 我正在尝试解决回文分割问题。您可以在https://leetcode.com/problems/palindrome- partitioning/中 找到问题。 我想出了解决方案: 但是性能很差。超过时间限制。 但是Python实现的相同想法可以通过: 这让我想知道如何改进swift的实现以及为什么swift的实现比python慢。 问题答案: Swift 是的集合,并且a 表示单
问题内容: 我正在使用Swift 3,并且需要与C API进行交互,例如,C API接受以NULL终止的字符串列表 在Swift中,API的导入方式如下 在尝试使用类型转换数百次后,我还是无法完成这项工作。即使我传递通过编译的有效指针,它也会在运行时崩溃,提示无效的内存访问(在strlen函数中)。还是关于ARC的东西? 问题答案: 您可以像如何通过使用char **参数将Swift字符串数组传递
问题内容: 我有一个String和一个int,可以说:和。什么是如果它们是相同的,看到的最快的方法还是(或者是有一个更快的方法?)? 这是Integer.parseInt和String.equals的源代码 问题答案: 会比 首先将num转换为O(n)的字符串,其中n是数字中的位数。然后它将再次进行字符串连接O(n),然后最终进行字符串比较。在这种情况下,字符串比较将是另一个O(n)-n是数字中的
问题内容: 我有阵列 转换为字符串: 串: 以及如何将此字符串转换回数组? 问题答案: 尝试我的stringToDeep()方法转换回Array。
问题内容: 在Java和C#之类的语言中,字符串是不可变的,并且一次建立一个字符的字符串在计算上是昂贵的。在上述语言中,有一些库类可以降低这种成本,例如C#和Java 。 php(4或5;我对两者都感兴趣)是否都共享此限制?如果是这样,是否有类似的解决方案? 问题答案: 不,在PHP中没有stringbuilder类的类型,因为字符串是可变的。 话虽如此,根据您在做什么,有不同的方式来构建字符串。