Swift 中 String 取下標及性能問題
取下標String
String 用 String.Index 取下標(subscript)得到 Character,String.Index 要從 String 中獲取
let greeting = "Guten Tag!"
greeting[greeting.startIndex] // Character "G"
greeting[greeting.index(before: greeting.endIndex)] // Character "!"
greeting[greeting.index(after: greeting.startIndex)] // Character "u"
let index = greeting.index(greeting.startIndex, offsetBy: 7)
greeting[index] // Character "a"
String 用 Range
Character String 通過 characters 屬性獲得 String.CharacterView,表示屏幕上顯示的內容。String.CharacterView 通過 String.CharacterView.Index 取下標得到 Character,String.CharacterView.Index 要從 String.CharacterView 中獲取let str = "abc"
str[str.startIndex..
let str = "abc"
let characters = str.characters // String.CharacterView
characters[characters.startIndex] // Character "a"
注意,String.CharacterView 不遵循 RandomAccessCollection 協議,用 String.CharacterView.Index 取下標不可以隨機訪問。另外,String.CharacterView.Index 與 String.Index 是相同的類型,屬於 Struct。String.Index 的文檔在 String 文檔下
typealias Index = String.CharacterView.Index
String.CharacterView 通過 Range
用 String.CharacterView 生成 Array Character 可以直接與 "a" 比較let str = "abc"
let characters = str.characters // String.CharacterView
let characters2 = characters[characters.startIndex..let str = "abc"
let arr = Array(str.characters) // Array
arr[1] // Character "b"
arr[1...2] // ArraySlice
String(arr) // String "abc"
let str = "abc"
let a = str[str.startIndex] // Character "a"
let b = str[str.index(str.startIndex, offsetBy: 1)] // Character "b"
a == "a" // true
b > "a" // true
UTF-8
String 通過 utf8 屬性獲得 String.UTF8View,表示 UTF-8 編碼的內容。String.UTF8View 通過 String.UTF8View.Index 取下標得到 UTF8.CodeUnit,實際上是 UInt8;通過 Range
let str = "abc"
let utf8 = str.utf8 // String.UTF8View
let n = utf8[utf8.startIndex] // UInt8 97
let a = utf8[utf8.startIndex..
let n2 = arr[0] // UInt8 97
let arr2 = arr[0...1] // // ArraySlice
String 通過 utf8CString 屬性獲得 ContiguousArray
let str = "abc"
let utf8 = str.utf8CString // ContiguousArray
let a = utf8[0] // Int8 97
let ab = utf8[0...1] // ArraySlice
UTF-16
String 通過 utf16 屬性獲得 String.UTF16View,表示 UTF-16 編碼的內容。String.UTF16View 通過 String.UTF16View.Index 取下標得到 UTF16.CodeUnit,實際上是 UInt16;通過 Range
let str = "abc"
let utf16 = str.utf16 // String.UTF16View
let n = utf16[utf16.startIndex] // UInt16 97
let a = utf16[utf16.startIndex..
let n2 = arr[0] // UInt16 97
let arr2 = arr[0...1] // // ArraySlice
性能對比
對 String、String.CharacterView、Array
定義測試類型、列印和更新時間的方法、要測試的 String
import Foundation
enum TestType {
case isEmpty
case count
case index
case range
}
func printAndUpdateTime(_ date: inout Date) {
let now = Date
print(now.timeIntervalSince(date))
date = now
}
let s = "aasdfsdfsdfgfdsg vrutj7edbj7 ergcwhmkl5lknjklqawkrcqjljkljqjlqjhbrlqwfcbhafcpiluioufnlkqjvjakjn fnvjalgkhlkdkjlkasdfsdfsdfgfdsg vrutj7edbj7 ergcwhmkl5lknjklqawkrcqjliopjktyuljqjlqjhbrlqwfcbhafciluioufnlkjvjakjn fnvjalgkhlkdkjlkasdfsdfsdfgfdsg vrutj7edbj7 ergcwhmkl5lknjklqawkrcqjljkljqjlqjhbrlqwfcbhafciluioufnlkjvjakjn fnvjalgkhlkdkjlkasderwytwghfsdfsdfgfdsg vrutj7edbj7 fdgotuyoergcwhmkl5lknjklqawkyrcqjljkljqjlqjhbrlqwfcbhafci luioufnlkjvjakjn fnvjalgkhlkdkjlkasdfsdfsdfgfdsg vrutj7edbj7 ergcvcnvbwhmkl5lknjklqawkrcqjljkljqjlqjhbrlqwfcbhafciluioufnlkjvjakjn fnvjalgkhlkdkjlkasdfsdfsdfgfdsg vrutj7edbj7 ergcwhmkl5lknjklqawkrcqjljkljqjlqjhbrlqwfcbhafciluioufnlkjvjakjkn fnvjalgkhlkdkjlkasdfsdfsdfgfdsg vrutj7edbj7 ergcwhmkl5lknjklqawkrcqjljkljqjlqjhbrlqwfcbhafciluioufnlkjvjakjn fnvjalgkhlkdkjlkasdfsdfsdfgfdsg iopiouvrutj7edbj7 ergcwhmkl5lknjklqawkrcqjljkfghngdljqjlqjhbrlqwfcbhafciluioufnlkjvjakjn fnvjalgkhlkdkjlkasdfsdfsdfgfdsg vrutj7edbj7 ergcwhmbkl5lknjklqawkrcqjljkljqjlqjhbrlqwfcbhafciluioufnlkjvjakjn fnvjalgkhlkdkjlkasdfsdfsdfgfdsg vrutj7edbj7 ergcwhmkl5lknjklqawkrcqjljkljqjlqjhbrlqwfcbhafciluioufnlkjvjakjn fnvjalgkhlkdkjlkasdfsdfsdfgfdsg vrutj7edbj7 ergcwhmkl5lknjklqawkrcqjljkljqjlqjhbrlqwfcbhafciluioufnlkjvjakjn fnvjalgkhlkdkjlkasdfsdfsdfgfdsg vrutj7edbj7 ergcwhmkl5lknjklqawkrcqjljkljqjlqjhbrlqwfcbhafciluioufnlkjvjakjn fnvjalgkhlkdkjlkasdfsdfsdfgfdsg vrutj7edbj7 ergcwhmkl5lknjklqasdfsdwkrcqjljkljqjlqjhbrlqwfcbhafciluioufnlkjvjakjn fnvjalgkhlkdkjlkasdfsdfsdfgfdsg vrutj7edbj7 ergcwhmkl5lknjklqawkrcqjljkljqjlqjhbrlqwfcbhafciluioufnlkjvjakjn fnvjalgkhlkdkjlkasdfsdfsdfgfdsg vrutj7edbj7 ergcwhmkl5lknjklqawkrcqjljkljdqjlqjhbrlqwfcbhafciluioufnlkjvjakjn fnvjalgkhlkdkjlkasddfsdfsdfgfdsg vrutj7edbj7 ergcwhmkl5lknjklqawkrcqjljkljqjlqjhbrlqwfcbhafciluioufnlkjvjakjn fnvjalgkhlkdkjlkasdfsdfsdfgfdsg vrutj7edbj7 ergcwhmkl5lknjklqawkrcqjljkljqjlqjhbsdfdsrlqwfcbhafciluioufnlkjvjakjn fnvjalgkhlkdkjlkasdfsdfsdfgfdsg vrutj7edbj7 ergcwhmkl5lknjklqawkrcqjljkljqjlqjhbrlqwfcbhafciluioufnlkjvjakjn fnvjalgkhlkdkjlkasdfsdfsdfgfdsg vrutj7edbj7 ergcwhmkl5lknjklqawkrcqjljkljqjlqjhbrlqwfcbhafciluioufnlkjvjakjn fnvjalgkhlkdkjlkasdfsdfsdfgfdsg vrutj7edbj7 ergcwhmkl5lknjklqawkrcqjljkljqjlqjhbrlqwfcbhafciluioufnlkjvjakjn fnvjalgkhlkdkjlkasdfsdfsdfsadfsdgfdsg vrutj7edbj7 ergcwhmkl5lknjklqawkrcqjljkljqsdfasjlqjhbrlqwfcbhafciluioufnlkjvjakjn fnvjalgkhlkdkjlkasdfsdfsdfgfdsg vrutj7edbj7 ergcwhmkl5lknjklqawkrcqjljkljqjlqjhbrlqwfcbhafciluioufnlkjvjakjn fnvjalgkhlkdkjlkasdfsdfsdfgfdsg vrutj7edbj7 ergcwhmkl5lknjklqawkrcqjljkljqjlqjhbrlqwfcbhafciluioufnlkjvjakjn fnvjalgkhlkdkjlkasdfsdfsdafgfdsg vrutj7edbj7 ergcwhmkl5lknjklqawkrcqjljkljqjlqjhbrlqwfcbhafciluioufnlkjvjakjn fnvjalgkhlkdkjlkasdfsdfsdfgfdsg vrutj7edbj7 ergcwhmkl5lknjklqawkrcqjljkljqjlqjhbrlqwfcbhafciluioufnlkjvjakjn fnvjalgkhlkdkjlkasdfsdfsdfgfdsg vrutj7edbj7 ergcwhmkl5lknjklqawkrcqjljkljqjlqjhbrlqwfcbhafciluioufnlkjvjakjn fnvjalgkhlkdkjlkasdfsdfsdfgfdsg vrutj7edbj7 ergcwhmkl5lknjklqawkrcqjljkljqjlqjhbrlqwfcbhafciluioufnlkjvjakjn fnvjalgkhlkdkjlk"
測試代碼
let loopCount = 10000
let index = s.characters.count / 2
let testType: TestType = .range
print(testType)
var date = Date
forLoop: for _ in 0.. 測試結果 判空 獲取長度
一個位置的取下標
一段距離的取下標
以上比較中,判斷 String 是否為空,訪問 String 的 isEmpty 速度最快。對於其他操作,遵循 RandomAccessCollection 協議(ContiguousArray
進一步比較判空操作
let loopCount = 10000
var date = Date
for _ in 0.. 與訪問 String 的 isEmpty 相比,判斷 String 是否等於空 String 速度更快! 注意到文檔中,對 String.UTF8View 和 String.UTF16View 的 Range 取下標方法的說明 如果 String 是從 Objective-C 的 NSString 橋接來的,時間複雜度為 O(n),否則為 O(1)。這句話怎麼理解呢?前面說了,String.UTF8View 不遵循 RandomAccessCollection 協議,而 String.UTF16View 遵循 RandomAccessCollection 協議,兩者的時間複雜度應該不同。這裡怎麼說時間複雜度與 String 是否橋接自 NSString 有關?以下進一步探究。 let loopCount = 10000 func test(_ s: String) { let utf8 = s.utf8 測試結果 對比 index 與 index2 的差異。測試參數 index2 約為 index 的 2 倍。UTF-8 index2 的耗時也約為 index 的 2 倍。UTF-16 的 index 和 index2 耗時相近。這與是否遵循 RandomAccessCollection 協議一致。 對比 String 與 NSString 的差異。橋接自 NSString 的 String 耗時比 String 要長,UTF-8 尤其明顯。這應該就是文檔說明的情況。用 Range 取下標,橋接自 NSString 的 String,比 String 多一些操作,多出 O(n) 級別的時間,而不是取下標的時間複雜度是 O(n)。 具體應用時,選取哪種編碼方式、取下標方式?首先,編碼方式要看具體應用場景。編碼方法不同,字元串的長度可能不同。如果字元串只含英文,比較好辦。如果字元串含有中文或 Emoji,選擇編碼方式就要慎重。注意,NSString 的 length 屬性獲得的長度對應 UTF-16 編碼。 let emojiStr = "????" let ChineseStr = "中文" 一般情況下,字元串要顯示出來,就用 String.CharacterView。如果要取下標,考慮性能,就用 String.CharacterView 生成 Array 現在 LeetCode 支持 Swift 了。如果做 LeetCode 的需要多次進行字元串取下標的題目,用不遵循 RandomAccessCollection 協議的類型(例如 String.CharacterView、String.UTF8View),可能思路對了結果卻是 「Time Limit Exceeded」。參見:http://www.cnblogs.com/silence-cnblogs/p/6878223.html 為了避免 NSString 橋接帶來的性能問題,在 Swift 里盡量用 String;盡量減少 Objective-C 的代碼,盡量選擇 Swift 編寫的第三方庫。subscript(bounds: Range
subscript(bounds: RangeComplexity: O(n) if the underlying string is bridged from Objective-C, where n is the length of the string; otherwise, O(1).
let s2 = NSString(string: s) as String
let index = s.characters.count / 2
let index2 = s.characters.count - 1
var date = Date
for _ in 0..let str = "abc"
str.characters.count // 3
str.unicodeScalars.count // 3
str.utf16.count // 3
(str as NSString).length // 3
str.utf8.count // 3
str.utf8CString.count - 1 // 3
strlen(str) // 3
emojiStr.characters.count // 1
emojiStr.unicodeScalars.count // 2
emojiStr.utf16.count // 4
(emojiStr as NSString).length // 4
emojiStr.utf8.count // 8
emojiStr.utf8CString.count - 1 // 8
strlen(emojiStr) // 8
ChineseStr.characters.count // 2
ChineseStr.unicodeScalars.count // 2
ChineseStr.utf16.count // 2
(ChineseStr as NSString).length // 2
ChineseStr.utf8.count // 6
ChineseStr.utf8CString.count - 1 // 6
strlen(ChineseStr) // 6
※.Net Core中使用ref和Span
※每天一道Java題「4」
※MySQL 的性能(上篇)——SQL 執行時間分析
※linux c++爬蟲(一)
※Azure Event Hub 技術研究系列2-發送事件到Event Hub
TAG:科技優家 |
※Salesforce 5大性能問題
※VMware workstation的性能優化
※在Salesforce Lightning Experience提高性能和速度
※利用Skywalking-netcore監控你的應用性能
※Red Hat:Meltdown和Spectre漏洞可能會影響性能
※使用 BenchmarkDotnet 測試代碼性能
※杉岩統一存儲推出SandStone AgileStore高性能引擎
※Microsoft Launcher 發布 提升性能 修復崩潰問題
※cephFS kernel client IO性能瓶頸分析
※微服務網關哪家強?一文看懂Zuul, Nginx, Spring Cloud, Linkerd性能差異
※BeatifulSoup,Xpath,CSS 選擇器的性能比較
※性能怪獸!全新配色 Air Jordan 18 「Yellow Suede」 實物亮相
※Volvo S60 T8 Polestar Engineeered,北極星性能轎跑!
※高振頻與高性能的絕美展現:蕭邦Superfast Chrono Porsche 919 Black Edition計時腕錶
※Galaxy S9樹立Android性能新標杆 但iPhone X仍然比它快
※Nike Epic React Flyknit 性能分析與搭配
※Facebook發布Tensor Comprehensions:自動編譯高性能機器學習核心的C+庫
※Oculus修復Rift當機問題,微軟改進SteamVR遊戲性能
※linux性能調試之iostat
※iPhone 7 Plus和iPhone X,性能區別?