I really like this idea, because indeed this wasn’t possible functionally 
before. I have a small remark though, wouldn’t it be better to let transform be 
of type (Key, Value) throws -> T instead of (Value) throws -> T? You can just 
ignore the key (with _) if you don’t need it, but I think it might come in 
handy in some cases.

> Hello everyone,
> 
> I have added a very simple, but powerful method into a Dictionary extension 
> on multiple projects in the last weeks, so I'd like to bring up the idea of 
> adding it into the standard library, in case other people can see its 
> benefits as well.
> 
> Currently, Dictionary conforms to Collection with its Element being the tuple 
> of Key and Value. Thus transforming the Dictionary with regular map results 
> in [T], whereas I'd find it more useful to also have a method which results 
> in [Key:T].
> 
> Let me present an example of where this makes sense.
> 
> I recently used the GitHub API to crawl some information about repositories. 
> I started with just names (e.g. "/apple/swift", "/apple/llvm") and fetched a 
> JSON response for each of the repos, each returning a dictionary, which got 
> saved into one large dictionary as the end of the full operation, keyed by 
> its name, so the structure was something like
> 
> {
> "/apple/swift": { "url":..., "size":...., "homepage":... },
> "/apple/llvm": { "url":..., "size":...., "homepage":... },
> ...
> }
> 
> To perform analysis, I just needed a dictionary mapping the name of the 
> repository to its size, freeing me to discard the rest of the results.
> This is where things get interesting, because you can't keep this action 
> nicely functional anymore. I had to do the following:
> 
> let repos: [String: JSON] = ...
> var sizes: [String: Int] = [:]
> for (key, value) in repos {
> sizes[key] = value["size"].int
> }
> // use sizes...
> 
> Which isn't a huge amount of work, but it creates unnecessary mutable state 
> in your transformation pipeline (and your current scope). And I had to write 
> it enough times to justify bringing it up on this list.
> 
> I suggest we add the following method to Dictionary:
> 
> extension Dictionary {
> public func mapValues<T>(_ transform: @noescape (Value) throws ->T) rethrows 
> ->[Key: T] {
> var transformed: [Key: T] = [:]
> for (key, value) in self {
> transformed[key] = try transform(value)
> }
> return transformed
> }
> }
> 
> It is modeled after Collection's `map` function, with the difference that
> a) only values are transformed, instead of the Key,Value tuple and
> b) the returned structure is a transformed Dictionary [Key:T], instead of [T]
> 
> This now allows a much nicer workflow:
> 
> let repos: [String: JSON] = ...
> var sizes = repos.mapValues { $0["size"].int }
> // use sizes...
> 
> and even multi-step transformations on Dictionaries, previously only possible 
> on Arrays, e.g.
> var descriptionTextLengths = repos.mapValues { $0["description"].string 
> }.mapValues { $0.characters.count }
> 
> You get the idea.
> 
> What do you think? I welcome all feedback, I'd like to see if people would 
> support it before I write a proper proposal.
> 
> Thanks! :)
> Honza Dvorsky
> 
> 
> 
> 
_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to