Created
October 27, 2016 06:44
-
-
Save rosslebeau/510b6392d669bbb565bd28c6c605ef47 to your computer and use it in GitHub Desktop.
A test of a grouping function showing how copy-on-write can slow your code down if you aren't vigilant.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Foundation | |
class SharedArray<T> { | |
var storage: [T] = [] | |
func append(_ value: T) { | |
storage.append(value) | |
} | |
} | |
public extension Sequence { | |
/** | |
Groups the elements in a `Sequence` by the provided `condition` | |
*/ | |
public func grouped<T: Hashable>(by condition: (Iterator.Element) -> T) -> [T: [Iterator.Element]] { | |
var result: [T: [Iterator.Element]] = [:] | |
for item in self { | |
let key = condition(item) | |
var items = result[key] ?? [] | |
items.append(item) | |
result[key] = items | |
} | |
return result | |
} | |
public func groupedNoCopy<T: Hashable>(by condition: (Iterator.Element) -> T) -> [T: [Iterator.Element]] { | |
var result: [T: [Iterator.Element]] = [:] | |
for item in self { | |
let key = condition(item) | |
var items = result.removeValue(forKey: key) ?? [] | |
items.append(item) | |
result[key] = items | |
} | |
return result | |
} | |
public func groupedWithWrapper<T: Hashable>(by condition: (Iterator.Element) -> T) -> [T: [Iterator.Element]] { | |
var groups: [T: SharedArray<Iterator.Element>] = [:] | |
for item in self { | |
let key = condition(item) | |
if let items = groups[key] { | |
items.append(item) | |
} else { | |
let items = SharedArray<Iterator.Element>() | |
items.append(item) | |
groups[key] = items | |
} | |
} | |
var result: [T: [Iterator.Element]] = [:] | |
for group in groups { | |
result[group.key] = group.value.storage | |
} | |
return result | |
} | |
} | |
let manyGroupsTest = {(item: Int) -> Int in | |
return item % 12000 | |
} | |
let fewGroupsTest = {(item: Int) -> Int in | |
return item % 2 | |
} | |
let copyManyGroupsStart = Date() | |
let copyManyGroups = (0 ..< 100_000).grouped(by: manyGroupsTest) | |
let copyManyGroupsEnd = Date() | |
print("Grouping with copy - many groups: \(copyManyGroupsEnd.timeIntervalSince(copyManyGroupsStart)) seconds") | |
let copyFewGroupsStart = Date() | |
let copyFewGroups = (0 ..< 100_000).grouped(by: fewGroupsTest) | |
let copyFewGroupsEnd = Date() | |
print("Grouping with copy - few groups: \(copyFewGroupsEnd.timeIntervalSince(copyFewGroupsStart)) seconds") | |
let noCopyManyGroupsStart = Date() | |
let noCopyManyGroups = (0 ..< 100_000).groupedNoCopy(by: manyGroupsTest) | |
let noCopyManyGroupsEnd = Date() | |
print("Grouping without copy - many groups: \(noCopyManyGroupsEnd.timeIntervalSince(noCopyManyGroupsStart)) seconds") | |
let noCopyFewGroupsStart = Date() | |
let noCopyFewGroups = (0 ..< 100_000).groupedNoCopy(by: fewGroupsTest) | |
let noCopyFewGroupsEnd = Date() | |
print("Grouping without copy - few groups: \(noCopyFewGroupsEnd.timeIntervalSince(noCopyFewGroupsStart)) seconds") | |
let wrappedManyGroupsStart = Date() | |
let wrappedManyGroups = (0 ..< 100_000).groupedWithWrapper(by: manyGroupsTest) | |
let wrappedManyGroupsEnd = Date() | |
print("Grouping with wrapper - many groups: \(wrappedManyGroupsEnd.timeIntervalSince(wrappedManyGroupsStart)) seconds") | |
let wrappedFewGroupsStart = Date() | |
let wrappedFewGroups = (0 ..< 100_000).groupedWithWrapper(by: fewGroupsTest) | |
let wrappedFewGroupsEnd = Date() | |
print("Grouping with wrapper - few groups: \(wrappedFewGroupsEnd.timeIntervalSince(wrappedFewGroupsStart)) seconds") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment