Space
When talking about performance, one should take space complexity into account. What's meant by this term is how much memory will be needed to run this piece of code and describes the relationship between the number of elements in the input and the reserved memory. For example, we talk about:
- O(n) space complexity when the reserved memory grows with the number of elements in the input.
- O(1) space complexity when the reserved memory doesn't grow when the number of the input elements grows.
Between replacingOccurrences(of: " ", with: "")
and components(separatedBy: .whitespaces).joined()
, the former wins on space complexity since the latter creates an intermidiary array, and in performance, less is more.
Time
Given this string :
let str = "Lorem ipsum dolor sit amet, tempor nulla integer morbi, amet non amet pede quis enim, ipsum in a in congue etiam, aenean orci wisi, habitant ipsum magna auctor quo odio leo. Urna nunc. Semper mauris felis vivamus dictumst. Tortor volutpat fringilla sed, lorem dui bibendum ligula faucibus massa, dis metus volutpat nec ridiculus, ac vel vitae. At pellentesque, at sed, fringilla erat, justo eu at porttitor vestibulum hac, morbi in etiam sed nam. Elit consectetuer lorem feugiat, ante turpis elit et pellentesque erat nec, vitae a fermentum vivamus ut. Orci donec nulla justo non id quis, ante vestibulum nec, volutpat a egestas pretium aliquam non sed, eget vivamus vestibulum, ornare sed tempus. Suscipit laoreet vivamus congue, tempor amet erat nulla, nostrum justo, wisi cras ac tempor tincidunt eu, hac faucibus convallis. Ac massa aenean nunc est orci, erat facilisis. Aliquam donec. Ut blandit potenti quam quis pellentesque, cursus imperdiet morbi ea ut, non mauris consectetuer mauris risus vehicula in, sed rutrum pellentesque turpis. Eros gravida volutpat justo proin donec penatibus, suspendisse fermentum sed proin fringilla libero malesuada, nulla lectus ligula, aliquam amet, nemo quis est. Quis imperdiet, class leo, lobortis etiam volutpat lacus wisi. Vestibulum vitae, nibh sem molestie natoque. Elementum ornare, rutrum quisque ultrices odio mauris condimentum et, auctor elementum erat ultrices. Ex gravida libero molestie facilisi rutrum, wisi quam penatibus, dignissim elementum elit mi, mauris est elit convallis. Non etiam mauris pretium id, tempus neque magna, tincidunt odio metus habitasse in maecenas nonummy. Suspendisse eget neque, pretium fermentum elementum."
The benchmarking code is given below. Each code block will be run separately, while the others will be commented out. :
do {
let start = Date()
let result = str.components(separatedBy: " ").joined()
let end = Date()
print(result.count, end.timeIntervalSince(start))
}
do {
let start = Date()
let result = str.split(separator: " ").joined()
let end = Date()
print(result.count, end.timeIntervalSince(start))
}
do {
let start = Date()
let result = str.filter { !$0.isWhitespace }
let end = Date()
print(s.count, end.timeIntervalSince(start))
}
do {
let start = Date()
var s = str
s.removeAll { $0.isWhitespace }
let end = Date()
print(s.count, end.timeIntervalSince(start))
}
do {
let start = Date()
let result = str.components(separatedBy: .whitespaces).joined()
let end = Date()
print(result.count, end.timeIntervalSince(start))
}
do {
let start = Date()
var result = ""
for char in str where char != " " {
result.append(char)
}
let end = Date()
print(result.count, end.timeIntervalSince(start))
}
do {
let start = Date()
let result = str.replacingOccurrences(of: " ", with: "")
let end = Date()
print(result.count, end.timeIntervalSince(start))
}
do {
let start = Date()
var arr = str.utf8CString
arr.removeAll(where: { $0 != 32 })
var result = ""
arr.withUnsafeBufferPointer { ptr in
result = String(cString: ptr.baseAddress!)
}
let end = Date()
print(result.count, end.timeIntervalSince(start))
}
Compiled with optimization in the terminal using this command:
xcrun swiftc -O ReplaceStr.swift -o replaceStr
-O
: with optimizations
ReplaceStr.swift
: the name of the file containing the code. You should cd
to the location of this file first.
-o
: to specify the name of the output compiled file
replaceStr
is an example name for the output file
And then run with ./replaceStr
After running each block multiple times, here are the best timings:
components(separatedBy: " ").joined() : 0.77ms
components(separatedBy: .whitespaces).joined() : 0.75ms
str.split(separator: " ").joined() : 0.54ms
filter { !$0.isWhitespace } : 0.52ms
removeAll { $0.isWhitespace } : 0.52ms
for char in str where char != " " : 0.26ms
replacingOccurrences(of: " ", with: "") : 0.23ms
str.utf8CString : 0.18ms
Comparable results were found with a shorter string :
let str = "Lorem ipsum dolor sit amet, tempor nulla integer morbi, amet non amet pede quis enim, ipsum in a in congue etiam, aenean orci wisi, habitant ipsum magna auctor quo odio leo."
Verdict
replacingOccurrences(of: " ", with: "")
is better than components(separatedBy: .whitespaces).joined()
in time complexity too. This is partially because replacingOccurrences(of:with:)
is defined on NSString
and not String
. In a sense it's like comparing to .
Manipulating the underlying CString beats them all and is the overall best.
For more on benchmarking code, here is a good thread.