In the absence of a solution without a custom type, you could do something like this (Swift 3.0.2):
struct DictionaryLazyMap<Key, Value, Transformed> where Key: Hashable {
typealias Source = [Key : Value]
typealias Transform = (Value) throws -> Transformed
private let source: Source
private let transform: Transform
init(source: Source, transform: @escaping Transform) {
self.source = source
self.transform = transform
}
// Swift <= 3.0.2 does not support throwing subscripts.
subscript(key: Key) -> Transformed? {
return (try? source[key].map(transform)) ?? nil
}
}
struct DictionaryLazyFlatMap<Key, Value, Transformed> where Key: Hashable {
typealias Source = [Key : Value]
typealias Transform = (Value) throws -> Transformed?
private let source: Source
private let transform: Transform
init(source: Source, transform: @escaping Transform) {
self.source = source
self.transform = transform
}
// Swift <= 3.0.2 does not support throwing subscripts.
subscript(key: Key) -> Transformed? {
return (try? source[key].flatMap(transform)) ?? nil
}
}
extension Dictionary {
func lazyMap<Transformed>(_ transform: @escaping DictionaryLazyMap<Key, Value, Transformed>.Transform) -> DictionaryLazyMap<Key, Value, Transformed> {
return DictionaryLazyMap(source: self, transform: transform)
}
func lazyFlatMap<Transformed>(_ transform: @escaping DictionaryLazyFlatMap<Key, Value, Transformed>.Transform) -> DictionaryLazyFlatMap<Key, Value, Transformed> {
return DictionaryLazyFlatMap(source: self, transform: transform)
}
}
let dictA = ["a": 25, "b": 42, "c": 6879]
let dictB = dictA.lazyMap { String($0 * 10) }
print(dictB["b"] as Any) // Optional("420")
print(dictB["x"] as Any) // nil
Swift 3.0.x doesn't allow a type definition to be nested inside an extension on a generic type, but 3.1 will.
Edit: Added a flatMap.