Forked from natecook1000/DictionaryObjectsForKeys.swift
Created
October 9, 2015 15:57
-
-
Save ggthedev/f2cb43c41e25d0ad04e3 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, | |
ValueCollection.Index.Distance == KeyCollection.Index.Distance> | |
(values: ValueCollection, forKeys keys: KeyCollection) | |
{ | |
// Return nil if the two collections aren't the same length. | |
guard keys.count == values.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() | |
repeat { | |
// 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() | |
// If the two sequences are the same length, they'll run | |
// out at the same time. Break cleanly. | |
if key == nil && value == nil { | |
break | |
} | |
// Now try to bind both values. If one fails there's a | |
// length mismatch, so we should return nil. | |
if let key = key, value = value { | |
self[key] = value | |
} else { | |
return nil | |
} | |
} while true | |
} | |
} | |
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