<div dir="ltr">This is a clarification on what I meant (I haven't had much time to test it, but I think it's representative):<div><br></div><div><a href="https://gist.github.com/therealbnut/c223d90a34bb14448b65fc6cc0ec70ac">https://gist.github.com/therealbnut/c223d90a34bb14448b65fc6cc0ec70ac</a><br></div><div><br></div><div>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.<div><br></div></div></div><div class="gmail_extra"><br><div class="gmail_quote">On Fri, Apr 15, 2016 at 2:23 AM, Dave Abrahams <span dir="ltr"><<a href="mailto:dabrahams@apple.com" target="_blank">dabrahams@apple.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span class=""><br>
on Wed Apr 13 2016, Andrew Bennett <cacoyi-AT-gmail.com> wrote:<br>
<br>
> I'm wondering if `Dictionary<String,Int>.Element`should be `Value`,<br>
> instead of `(Key,Value)`.<br>
<br>
<br>
</span>I think(?) it's fairly unprecedented. Python sets the<br>
*opposite* precedent, FWIW (a dict is a sequence of its keys).<br>
<br>
One possible upside is that Dictionary becomes a MutableCollection.<br>
<span class=""><br>
> With an array you can do this:<br>
><br>
> for (key, value) in ["a", "b", "c"].enumerate() {<br>
><br>
> print(key, value) // 0 a, 1 b, 2 c<br>
><br>
> }<br>
><br>
> Shouldn't the equivalent for a dictionary be this?<br>
><br>
> for (key, value) in ["a": 0, "b": 1, "c": 2].enumerate() {<br>
><br>
> print(key, value) // a 0, b 1, c 2<br>
><br>
> }<br>
<br>
</span>Not unless you can come up with a generic definition of the semantics of<br>
enumerate() that allows the first element of the pair to be the index in<br>
some cases and the key in others. Right now, enumerate() works on<br>
sequences, which you would probably have to drop. Also, don't forget,<br>
Dictionaries still need indices distinct from their keys, because you<br>
shouldn't have to do a hash lookup just to advance to the next element.<br>
<span class=""><br>
> Not this:<br>
><br>
> for (key, value) in ["a": 0, "b": 1, "c": 2] {<br>
><br>
> print(key, value) // a 0, b 1, c 2<br>
><br>
> }<br>
><br>
> Presumably the old syntax would produce only values:<br>
><br>
> for value in ["a": 0, "b": 1, "c": 2] {<br>
><br>
> print(value) // 0, 1, 2<br>
><br>
> }<br>
><br>
> You can still iterate the keys like this:<br>
><br>
> for key in ["a": 0, "b": 1, "c": 2].keys {<br>
><br>
> print(key) // a, b, c<br>
><br>
> }<br>
<br>
</span>To get them both, I suppose you'd write zip(d.keys, d.values).<br>
<span class=""><br>
> I think I understand the reasoning for Dictionary the way it is, but I<br>
> think it only provides consistency to the implementation, not the<br>
> interface.<br>
<br>
</span>Dictionary was not defined the way it is for implementation reasons. In<br>
fact, the keys and values are currently stored in separate arrays. You<br>
are suggesting a different conceptual model for dictionaries, and it<br>
might even be an improvement, but that doesn't mean the current design<br>
is implementation-driven.<br>
<span class=""><br>
> The result of all this being that Dictionary is more consistent (IMO), and map<br>
> would work on the values of all collection types, not a mix of values and<br>
> key/value pairs.<br>
><br>
> What do you think?<br>
<br>
</span>It's an interesting idea, worthy of consideration. I suspect there are<br>
probably lots more arguments to be made here, that haven't occurred to<br>
either of us yet, and maybe some serious downsides. I hope to hear more<br>
about it from others.<br>
<div class="HOEnZb"><div class="h5"><br>
> On Thu, Apr 14, 2016 at 9:07 AM, Dave Abrahams via swift-evolution<br>
> <<a href="mailto:swift-evolution@swift.org">swift-evolution@swift.org</a>> wrote:<br>
><br>
> on Wed Apr 13 2016, Nate Cook <<a href="mailto:swift-evolution@swift.org">swift-evolution@swift.org</a>> wrote:<br>
><br>
> > On Apr 13, 2016, at 12:02 PM, Jacob Bandes-Storch via swift-evolution<br>
> > <<a href="mailto:swift-evolution@swift.org">swift-evolution@swift.org</a>> wrote:<br>
> ><br>
> > To adhere to the API Design Guidelines, I think it should be named<br>
> > "mappingValues", right?<br>
> ><br>
> > On Wed, Apr 13, 2016 at 4:23 AM, Vladimir.S via swift-evolution<br>
> > <<a href="mailto:swift-evolution@swift.org">swift-evolution@swift.org</a>> wrote:<br>
> ><br>
> > As for mapKeys and many values into a single key. I believe we should have<br>
> a<br>
> > choice - do we expect multiply values for the same key or not. Just like<br>
> > "+" and integer overflow : by default it raises the error, but if "&+" -<br>
> > we expect the overflow. I can imagine situations when it is ok for me to<br>
> > have different values for the same key(if I don't care which of values<br>
> > should be for that key in result dictionary).<br>
> > So my proposal is some additional mapKey(allowMultiplyValues: true)<br>
> > {...} or in any other form/name.<br>
> ><br>
> > There's a proposal (awaiting merging) to add Dictionary initializers and<br>
> methods<br>
> > that work with key/value pairs. These provide different ways of dealing<br>
> with the<br>
> > duplicate key issue after a call to the regular Collection.map method.<br>
> ><br>
> ><br>
> <a href="https://github.com/natecook1000/swift-evolution/blob/natecook-dictionary-merge/proposals/0000-add-sequence-based-init-and-merge-to-dictionary.md" rel="noreferrer" target="_blank">https://github.com/natecook1000/swift-evolution/blob/natecook-dictionary-merge/proposals/0000-add-sequence-based-init-and-merge-to-dictionary.md</a><br>
><br>
> Ah, yes, that reminds me of your answer to the question about whether we<br>
> need a “uniquingKeys” label on that init(), which IMO is a good one: no,<br>
> we don't need it, because the one without the label traps on duplicate<br>
> keys.<br>
><br>
> > I'd be interested in a `mapValues` or `transformValues` method that would<br>
> modify<br>
> > values in place while leaving keys alone.<br>
><br>
> Is that enough of an improvement over<br>
><br>
> Dictionary(d.lazy.map { (k,v) in (k, transform(v)) })<br>
><br>
> (once we get that initializer) to make it worth expanding the Dictionary<br>
> API?<br>
><br>
> > Another useful method (that could be used to build mapValues more<br>
> efficiently)<br>
> > would be `Dictionary.updateValue(value: Value, at index: DictionaryIndex)<br>
> `, so<br>
> > you could write:<br>
> ><br>
> > var dict = ["a": 1, "b": 2, "c": 3]<br>
> > if let i = dict.index(where: { $0.value == 3 }) {<br>
> > dict.updateValue(100, at: i)<br>
> > }<br>
> > // dict == ["a": 1, "b": 2, "c": 100]<br>
><br>
> Indeed it would!<br>
><br>
> > -Nate<br>
> ><br>
> > On 13.04.2016 13:38, Ross O'Brien via swift-evolution wrote:<br>
> ><br>
> > +1 on mapValues.<br>
> ><br>
> > DictionaryLiteral already throws an exception if it includes<br>
> > duplicate<br>
> > keys, so I'd expect mapKeys to throw an error if multiple source<br>
> > keys<br>
> > mapped to the same destination key.<br>
> ><br>
> > On Wed, Apr 13, 2016 at 11:28 AM, Miguel Angel Quinones via<br>
> > swift-evolution<br>
> > <<a href="mailto:swift-evolution@swift.org">swift-evolution@swift.org</a><br>
> > <mailto:<a href="mailto:swift-evolution@swift.org">swift-evolution@swift.org</a>>><br>
> > wrote:<br>
> ><br>
> > I'm +1 for adding mapValues. Very useful functionality and trivial<br>
> > to<br>
> > implement.<br>
> ><br>
> > > > I.e. I suggest to implement and mapKeys() also. It could be also<br>
> > useful in some situations.<br>
> > > `mapKeys` is much more dangerous, because you could end up mapping<br>
> > many values into a single key. You kind of need to combine the<br>
> > values somehow. Perhaps:<br>
> > ><br>
> > > extension Dictionary {<br>
> > > func mapValues__(_ valueTransform: @noescape Value throws<br>
> > ->OutValue) rethrows ->[Key: OutValue] { … }<br>
> > ><br>
> > > func mapKeys__(_ keyTransform: @noescape Key throws ->OutKey)<br>
> > rethrows ->[OutKey: [Value]] { … }<br>
> > ><br>
> > > // Possibly flatMap variants, too?<br>
> > > }<br>
> > ><br>
> > > extension Dictionary where Value: Sequence {<br>
> > > func reduceValues__(_ initial: OutValue, combine: @noescape<br>
> > (OutValue, Value.Iterator.Element) throws ->OutValue) rethrows -><br>
> > [Key:<br>
> > OutValue] {<br>
> > > return mapValues { $0.reduce(initial, combine: combine) }<br>
> > > }<br>
> > > }<br>
> > ><br>
> > > Which you would end up using like this:<br>
> > ><br>
> > > let wordFrequencies: [String: Int] = …<br>
> > > let firstLetterFrequencies: [Character: Int] =<br>
> > wordFrequencies.mapKeys { $0.characters.first! }.reduceValues(0,<br>
> > combine: +)<br>
> > ><br>
> > > --<br>
> > > Brent Royal-Gordon<br>
> > > Architechies<br>
> > ><br>
> > ><br>
> > ><br>
> > >______<br>
> ><br>
> > --<br>
> > Miguel Angel Quinones<br>
> ><br>
> > _______________________________________________<br>
> > swift-evolution mailing list<br>
> > <a href="mailto:swift-evolution@swift.org">swift-evolution@swift.org</a><br>
> > <mailto:<a href="mailto:swift-evolution@swift.org">swift-evolution@swift.org</a>><br>
> > <a href="https://lists.swift.org/mailman/listinfo/swift-evolution" rel="noreferrer" target="_blank">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br>
> ><br>
> > _______________________________________________<br>
> > swift-evolution mailing list<br>
> > <a href="mailto:swift-evolution@swift.org">swift-evolution@swift.org</a><br>
> > <a href="https://lists.swift.org/mailman/listinfo/swift-evolution" rel="noreferrer" target="_blank">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br>
> ><br>
> > _______________________________________________<br>
> > swift-evolution mailing list<br>
> > <a href="mailto:swift-evolution@swift.org">swift-evolution@swift.org</a><br>
> > <a href="https://lists.swift.org/mailman/listinfo/swift-evolution" rel="noreferrer" target="_blank">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br>
> ><br>
> > _______________________________________________<br>
> > swift-evolution mailing list<br>
> > <a href="mailto:swift-evolution@swift.org">swift-evolution@swift.org</a><br>
> > <a href="https://lists.swift.org/mailman/listinfo/swift-evolution" rel="noreferrer" target="_blank">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br>
> ><br>
> > _______________________________________________<br>
> > swift-evolution mailing list<br>
> > <a href="mailto:swift-evolution@swift.org">swift-evolution@swift.org</a><br>
> > <a href="https://lists.swift.org/mailman/listinfo/swift-evolution" rel="noreferrer" target="_blank">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br>
><br>
> --<br>
> Dave<br>
><br>
> _______________________________________________<br>
> swift-evolution mailing list<br>
> <a href="mailto:swift-evolution@swift.org">swift-evolution@swift.org</a><br>
> <a href="https://lists.swift.org/mailman/listinfo/swift-evolution" rel="noreferrer" target="_blank">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br>
><br>
<br>
</div></div><span class="HOEnZb"><font color="#888888">--<br>
Dave<br>
</font></span></blockquote></div><br></div>