<div dir="ltr">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.<br><br>
<p style="margin:0px;line-height:normal">I'm wondering if <font face="Menlo"><span style="font-size:11px">`Dictionary<String,Int>.Element`</span></font>should be <span style="font-family:Menlo;font-size:11px">`Value`, </span>instead of <font face="Menlo"><span style="font-size:11px">`(Key,Value)`</span></font>.</p>
<p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo;min-height:13px"><span style=""></span><br></p>
With an array you can do this:<div><br>
<p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo"><span style="color:rgb(187,44,162)">for</span><span style=""> (key, value) </span><span style="color:rgb(187,44,162)">in</span><span style=""> [</span><span style="color:rgb(209,47,27)">"a"</span><span style="">, </span><span style="color:rgb(209,47,27)">"b"</span><span style="">, </span><span style="color:rgb(209,47,27)">"c"</span><span style="">].</span><span style="color:rgb(61,29,129)">enumerate</span><span style="">() {</span></p>
<p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo"><span style=""> </span><span style="color:rgb(61,29,129)">print</span><span style="">(key, value) </span><span style="color:rgb(0,132,0)">// 0 a, 1 b, 2 c</span></p>
<p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo"><span style="">}</span></p>
<p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo;min-height:13px"><span style=""></span><br></p>
Shouldn't the equivalent for a dictionary be this?
<p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo;min-height:13px"><span style=""></span><br></p>
<p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo"><span style="color:rgb(187,44,162)">for</span><span style=""> (key, value) </span><span style="color:rgb(187,44,162)">in</span><span style=""> [</span><span style="color:rgb(209,47,27)">"a"</span><span style="">: </span><span style="color:rgb(39,42,216)">0</span><span style="">, </span><span style="color:rgb(209,47,27)">"b"</span><span style="">: </span><span style="color:rgb(39,42,216)">1</span><span style="">, </span><span style="color:rgb(209,47,27)">"c"</span><span style="">: </span><span style="color:rgb(39,42,216)">2</span><span style="">].</span><span style="color:rgb(61,29,129)">enumerate</span><span style="">() {</span></p>
<p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo"><span style=""> </span><span style="color:rgb(61,29,129)">print</span><span style="">(key, value) </span><span style="color:rgb(0,132,0)">// a 0, b 1, c 2</span></p>
<p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo"><span style="">}</span></p>
<p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo;min-height:13px"><span style=""></span><br></p>
Not this:
<p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo;min-height:13px"><span style=""></span><br></p>
<p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo"><span style="color:rgb(187,44,162)">for</span><span style=""> (key, value) </span><span style="color:rgb(187,44,162)">in</span><span style=""> [</span><span style="color:rgb(209,47,27)">"a"</span><span style="">: </span><span style="color:rgb(39,42,216)">0</span><span style="">, </span><span style="color:rgb(209,47,27)">"b"</span><span style="">: </span><span style="color:rgb(39,42,216)">1</span><span style="">, </span><span style="color:rgb(209,47,27)">"c"</span><span style="">: </span><span style="color:rgb(39,42,216)">2</span><span style="">] {</span></p>
<p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo"><span style=""> </span><span style="color:rgb(61,29,129)">print</span><span style="">(key, value) </span><span style="color:rgb(0,132,0)">// a 0, b 1, c 2</span></p>
<p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo"><span style="">}</span></p><p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo"><span style=""><br></span></p>Presumably the old syntax would produce only values:<p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo"><br></p><p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo"><span style="color:rgb(187,44,162)">for</span> value <span style="color:rgb(187,44,162)">in</span> [<span style="color:rgb(209,47,27)">"a"</span>: <span style="color:rgb(39,42,216)">0</span>, <span style="color:rgb(209,47,27)">"b"</span>: <span style="color:rgb(39,42,216)">1</span>, <span style="color:rgb(209,47,27)">"c"</span>: <span style="color:rgb(39,42,216)">2</span>] {</p><p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo"> <span style="color:rgb(61,29,129)">print</span>(value) <span style="color:rgb(0,132,0)">// 0, 1, 2</span></p><p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo">}</p><p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo"><br></p>You can still iterate the keys like this:<p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo"><br></p><p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo"><span style="color:rgb(187,44,162)">for</span> key <span style="color:rgb(187,44,162)">in</span> [<span style="color:rgb(209,47,27)">"a"</span>: <span style="color:rgb(39,42,216)">0</span>, <span style="color:rgb(209,47,27)">"b"</span>: <span style="color:rgb(39,42,216)">1</span>, <span style="color:rgb(209,47,27)">"c"</span>: <span style="color:rgb(39,42,216)">2</span>].keys {</p><p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo"> <span style="color:rgb(61,29,129)">print</span>(key) <span style="color:rgb(0,132,0)">// a, b, c</span></p><p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo">}</p><div><br></div>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.</div><div><br></div><div>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.</div><div><br></div><div>What do you think?<br><p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo"><span style=""><br></span></p></div></div><div class="gmail_extra"><br><div class="gmail_quote">On Thu, Apr 14, 2016 at 9:07 AM, Dave Abrahams via swift-evolution <span dir="ltr"><<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</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, 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 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 methods<br>
> that work with key/value pairs. These provide different ways of dealing with the<br>
> duplicate key issue after a call to the regular Collection.map method.<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>
</span>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>
<span class=""><br>
> I'd be interested in a `mapValues` or `transformValues` method that would modify<br>
> values in place while leaving keys alone.<br>
<br>
</span>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>
<span class=""><br>
> Another useful method (that could be used to build mapValues more efficiently)<br>
> would be `Dictionary.updateValue(value: Value, at index: DictionaryIndex)`, 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>
</span>Indeed it would!<br>
<div class="HOEnZb"><div class="h5"><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>
</div></div><span class="HOEnZb"><font color="#888888">--<br>
Dave<br>
</font></span><div class="HOEnZb"><div class="h5"><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>
</div></div></blockquote></div><br></div>