Last active
December 9, 2015 18:43
-
-
Save natecook1000/92d495d9b95e35ee77db to your computer and use it in GitHub Desktop.
Initializers for Dictionary like NSDictionary +dictionaryWithObjects:forKeys:
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
// (c) 2015 Nate Cook, licensed under the MIT license | |
// | |
// Initializers for Dictionary like NSDictionary +dictionaryWithObjects:forKeys: | |
public extension Dictionary { | |
/// Creates a new Dictionary from the given `keys` and `values` collections. | |
/// | |
/// More efficient than the sequence version because it can reserve the correct | |
/// capacity before filling the dictionary. Returns `nil` if the lengths of the | |
/// two collections differ. | |
init?<ValueCollection: CollectionType, KeyCollection: CollectionType | |
where ValueCollection.Generator.Element == Value, KeyCollection.Generator.Element == Key> | |
(values: ValueCollection, forKeys keys: KeyCollection) | |
{ | |
// Return nil if the two collections aren't the same length. | |
guard values.count == numericCast(keys.count) | |
else { return nil } | |
self = Dictionary(minimumCapacity: numericCast(keys.count)) | |
for (key, value) in zip(keys, values) { | |
self[key] = value | |
} | |
} | |
/// Creates a new Dictionary from the given `keys` | |
/// and `values` sequences. | |
/// | |
/// Returns `nil` if the lengths of the two sequences differ. | |
init?<ValueSequence: SequenceType, KeySequence: SequenceType | |
where ValueSequence.Generator.Element == Value, KeySequence.Generator.Element == Key> | |
(values: ValueSequence, forKeys keys: KeySequence) | |
{ | |
self = Dictionary() | |
// If we use zip with sequences, we won't know if there's a | |
// length mismatch, so we need to use their generators manually. | |
var keyGenerator = keys.generate() | |
var valueGenerator = values.generate() | |
while true { | |
// If we use optional binding here, we won't be able to | |
// distinguish the case where both run out together (i.e., | |
// the same length) from where one runs out first. | |
let key = keyGenerator.next() | |
let value = valueGenerator.next() | |
switch (key, value) { | |
// If key and value both bind, we can add the pair to | |
// the dictionary. | |
case let (.Some(key), .Some(value)): | |
self[key] = value | |
// If the two sequences run out at the same time, they | |
// were the same length: return cleanly. | |
case (.None, .None): | |
return | |
// Otherwise, one sequence bound and the other didn't, | |
// so return nil. | |
default: | |
return nil | |
} | |
} | |
} | |
} | |
let keys = ["one", "two", "three"] | |
let values = [1, 2, 3] | |
let moreValues = values + [4] | |
// these succeed | |
let dict1 = Dictionary(values: values, forKeys: keys) | |
let dict2 = Dictionary(values: AnySequence(values), forKeys: keys) | |
// these fail, since moreValues.count > keys.count | |
let dict3 = Dictionary(values: moreValues, forKeys: keys) | |
let dict4 = Dictionary(values: AnySequence(moreValues), forKeys: keys) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment