Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save ggthedev/f2cb43c41e25d0ad04e3 to your computer and use it in GitHub Desktop.
Save ggthedev/f2cb43c41e25d0ad04e3 to your computer and use it in GitHub Desktop.
Initializers for Dictionary like NSDictionary +dictionaryWithObjects:forKeys:
// (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