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