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