[swift-evolution] [Proposal] mapValues

Andrew Bennett cacoyi at gmail.com
Wed Apr 13 18:37:25 CDT 2016


I don't think I've ever called map on a dictionary in production code, only
a mapValue function like this thread discusses. When do we actually want to
call map on a dictionary? I feel like mapValue should be the default.

I'm wondering if `Dictionary<String,Int>.Element`should be `Value`, instead
of `(Key,Value)`.


With an array you can do this:

for (key, value) in ["a", "b", "c"].enumerate() {

    print(key, value) // 0 a, 1 b, 2 c

}


Shouldn't the equivalent for a dictionary be this?


for (key, value) in ["a": 0, "b": 1, "c": 2].enumerate() {

    print(key, value) // a 0, b 1, c 2

}


Not this:


for (key, value) in ["a": 0, "b": 1, "c": 2] {

    print(key, value) // a 0, b 1, c 2

}


Presumably the old syntax would produce only values:


for value in ["a": 0, "b": 1, "c": 2] {

    print(value) // 0, 1, 2

}


You can still iterate the keys like this:


for key in ["a": 0, "b": 1, "c": 2].keys {

    print(key) // a, b, c

}

I think I understand the reasoning for Dictionary the way it is, but I
think it only provides consistency to the implementation, not the interface.

The result of all this being that Dictionary is more consistent (IMO), and
map would work on the values of all collection types, not a mix of values
and key/value pairs.

What do you think?



On Thu, Apr 14, 2016 at 9:07 AM, Dave Abrahams via swift-evolution <
swift-evolution at swift.org> wrote:

>
> on Wed Apr 13 2016, Nate Cook <swift-evolution at swift.org> wrote:
>
> >     On Apr 13, 2016, at 12:02 PM, Jacob Bandes-Storch via swift-evolution
> >     <swift-evolution at swift.org> wrote:
> >
> >     To adhere to the API Design Guidelines, I think it should be named
> >     "mappingValues", right?
> >
> >     On Wed, Apr 13, 2016 at 4:23 AM, Vladimir.S via swift-evolution
> >     <swift-evolution at swift.org> wrote:
> >
> >     As for mapKeys and many values into a single key. I believe we
> should have a
> >         choice - do we expect multiply values for the same key or not.
> Just like
> >         "+" and integer overflow : by default it raises the error, but
> if "&+" -
> >         we expect the overflow. I can imagine situations when it is ok
> for me to
> >         have different values for the same key(if I don't care which of
> values
> >         should be for that key in result dictionary).
> >         So my proposal is some additional mapKey(allowMultiplyValues:
> true)
> >         {...} or in any other form/name.
> >
> > There's a proposal (awaiting merging) to add Dictionary initializers and
> methods
> > that work with key/value pairs. These provide different ways of dealing
> with the
> > duplicate key issue after a call to the regular Collection.map method.
> >
> >
> https://github.com/natecook1000/swift-evolution/blob/natecook-dictionary-merge/proposals/0000-add-sequence-based-init-and-merge-to-dictionary.md
>
> Ah, yes, that reminds me of your answer to the question about whether we
> need a “uniquingKeys” label on that init(), which IMO is a good one: no,
> we don't need it, because the one without the label traps on duplicate
> keys.
>
> > I'd be interested in a `mapValues` or `transformValues` method that
> would modify
> > values in place while leaving keys alone.
>
> Is that enough of an improvement over
>
>    Dictionary(d.lazy.map { (k,v) in (k, transform(v)) })
>
> (once we get that initializer) to make it worth expanding the Dictionary
> API?
>
> > Another useful method (that could be used to build mapValues more
> efficiently)
> > would be `Dictionary.updateValue(value: Value, at index:
> DictionaryIndex)`, so
> > you could write:
> >
> > var dict = ["a": 1, "b": 2, "c": 3]
> > if let i = dict.index(where: { $0.value == 3 }) {
> > dict.updateValue(100, at: i)
> > }
> > // dict == ["a": 1, "b": 2, "c": 100]
>
> Indeed it would!
>
> > -Nate
> >
> >         On 13.04.2016 13:38, Ross O'Brien via swift-evolution wrote:
> >
> >         +1 on mapValues.
> >
> >             DictionaryLiteral already throws an exception if it includes
> >             duplicate
> >             keys, so I'd expect mapKeys to throw an error if multiple
> source
> >             keys
> >             mapped to the same destination key.
> >
> >             On Wed, Apr 13, 2016 at 11:28 AM, Miguel Angel Quinones via
> >             swift-evolution
> >             <swift-evolution at swift.org
> >             <mailto:swift-evolution at swift.org>>
> >             wrote:
> >
> >             I'm +1 for adding mapValues. Very useful functionality and
> trivial
> >             to
> >             implement.
> >
> >             > > I.e. I suggest to implement and mapKeys() also. It could
> be also
> >             useful in some situations.
> >             > `mapKeys` is much more dangerous, because you could end up
> mapping
> >             many values into a single key. You kind of need to combine
> the
> >             values somehow. Perhaps:
> >             >
> >             > extension Dictionary {
> >             > func mapValues__(_ valueTransform: @noescape Value throws
> >             ->OutValue) rethrows ->[Key: OutValue] { … }
> >             >
> >             > func mapKeys__(_ keyTransform: @noescape Key throws
> ->OutKey)
> >             rethrows ->[OutKey: [Value]] { … }
> >             >
> >             > // Possibly flatMap variants, too?
> >             > }
> >             >
> >             > extension Dictionary where Value: Sequence {
> >             > func reduceValues__(_ initial: OutValue, combine: @noescape
> >             (OutValue, Value.Iterator.Element) throws ->OutValue)
> rethrows ->
> >             [Key:
> >             OutValue] {
> >             > return mapValues { $0.reduce(initial, combine: combine) }
> >             > }
> >             > }
> >             >
> >             > Which you would end up using like this:
> >             >
> >             > let wordFrequencies: [String: Int] = …
> >             > let firstLetterFrequencies: [Character: Int] =
> >             wordFrequencies.mapKeys { $0.characters.first!
> }.reduceValues(0,
> >             combine: +)
> >             >
> >             > --
> >             > Brent Royal-Gordon
> >             > Architechies
> >             >
> >             >
> >             >
> >             >______
> >
> >             --
> >             Miguel Angel Quinones
> >
> >             _______________________________________________
> >             swift-evolution mailing list
> >             swift-evolution at swift.org
> >             <mailto:swift-evolution at swift.org>
> >             https://lists.swift.org/mailman/listinfo/swift-evolution
> >
> >             _______________________________________________
> >             swift-evolution mailing list
> >             swift-evolution at swift.org
> >             https://lists.swift.org/mailman/listinfo/swift-evolution
> >
> >         _______________________________________________
> >         swift-evolution mailing list
> >         swift-evolution at swift.org
> >         https://lists.swift.org/mailman/listinfo/swift-evolution
> >
> >     _______________________________________________
> >     swift-evolution mailing list
> >     swift-evolution at swift.org
> >     https://lists.swift.org/mailman/listinfo/swift-evolution
> >
> > _______________________________________________
> > swift-evolution mailing list
> > swift-evolution at swift.org
> > https://lists.swift.org/mailman/listinfo/swift-evolution
>
> --
> Dave
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160414/61f44e19/attachment.html>


More information about the swift-evolution mailing list