I have two versions of a loop over a generic Dictionary
collection in Swift. I am not happy about the refactored version because it has the overhead of creating a new Array
object out of the LazyBidirectionalCollection
returned by dict.keys.
On the other hand it's possible there is no real extra overhead and I doth protest too much. On the third hand, I'd love to understand this deeply enough that I know a) one cannot avoid creating the Array or b) there's a way but it may have other drawbacks.
func dump1<Key, Val where Key: Hashable, Key: Comparable>(dict: [Key: Val], sort: Bool = true) -> String {
var d = ""
if sort {
for k in sorted(dict.keys, {$0 < $1}) {
d += "\(k): \(dict[k]!)\n"
}
}
else {
for k in dict.keys {
d += "\(k): \(dict[k]!)\n"
}
}
return d
}
func dump2<Key, Val where Key: Hashable, Key: Comparable>(dict: [Key: Val], sort: Bool = true) -> String {
var d = ""
var keys = sort ? sorted(dict.keys, {$0 < $1}) : Array(dict.keys)
for k in keys {
d += "\(k): \(dict[k]!)\n"
}
return d
}
Thanks to Mr. AirSpeed (http://airspeedvelocity.net/2014/07/28/collection-and-sequence-helpers/), type erasure is what I was missing:
func dumpIt<Key, Val where Key: Hashable, Key: Comparable>(dict: [Key: Val], sort: Bool = true) -> String {
var printOut = ""
for k in sort ? SequenceOf(sorted(dict.keys) {$0 < $1}) : SequenceOf(dict.keys) {
printOut += "\(k): \(dict[k]!) "
}
return printOut
}
Although a follow-up question is, if I want to use reduce
rather than a for-loop, but I still don't want to create an Array, how can I create a type-erased Collection
view on the above sequences.
Anyway, if the array version is just as efficient, this is probably preferable notation:
func dumpIt2<Key, Val where Key: Hashable, Key: Comparable>(dict: [Key: Val], sort: Bool = true) -> String {
return (sort ? sorted(dict.keys) {$0 < $1} : Array(dict.keys)).reduce("") { $0 + "\($1): \(dict[$1]!) " }
}