[swift-evolution] [Proposal] mapValues

Andrew Bennett cacoyi at gmail.com
Fri Apr 15 06:53:15 CDT 2016


This is a clarification on what I meant (I haven't had much time to test
it, but I think it's representative):

https://gist.github.com/therealbnut/c223d90a34bb14448b65fc6cc0ec70ac

Sorry if I've derailed this conversation, I'm in support of mapValues, but
I feel like map itself should be mapping the values. Let me know if I
should discuss this in another thread.


On Fri, Apr 15, 2016 at 2:23 AM, Dave Abrahams <dabrahams at apple.com> wrote:

>
> on Wed Apr 13 2016, Andrew Bennett <cacoyi-AT-gmail.com> wrote:
>
> > I'm wondering if `Dictionary<String,Int>.Element`should be `Value`,
> > instead of `(Key,Value)`.
>
>
> I think(?) it's fairly unprecedented.  Python sets the
> *opposite* precedent, FWIW (a dict is a sequence of its keys).
>
> One possible upside is that Dictionary becomes a MutableCollection.
>
> > 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 unless you can come up with a generic definition of the semantics of
> enumerate() that allows the first element of the pair to be the index in
> some cases and the key in others.  Right now, enumerate() works on
> sequences, which you would probably have to drop.  Also, don't forget,
> Dictionaries still need indices distinct from their keys, because you
> shouldn't have to do a hash lookup just to advance to the next element.
>
> > 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
> >
> > }
>
> To get them both, I suppose you'd write zip(d.keys, d.values).
>
> > 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.
>
> Dictionary was not defined the way it is for implementation reasons.  In
> fact, the keys and values are currently stored in separate arrays.  You
> are suggesting a different conceptual model for dictionaries, and it
> might even be an improvement, but that doesn't mean the current design
> is implementation-driven.
>
> > 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?
>
> It's an interesting idea, worthy of consideration.  I suspect there are
> probably lots more arguments to be made here, that haven't occurred to
> either of us yet, and maybe some serious downsides.  I hope to hear more
> about it from others.
>
> > 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
> >
>
> --
> Dave
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160415/999f6c41/attachment.html>


More information about the swift-evolution mailing list