[swift-evolution] Dictionary Enhancements

Nate Cook natecook at gmail.com
Sun Feb 19 21:22:03 CST 2017


> On Feb 19, 2017, at 6:13 PM, Ben Cohen via swift-evolution <swift-evolution at swift.org> wrote:
> 
>> On Feb 19, 2017, at 11:22 AM, Ole Begemann <ole at oleb.net <mailto:ole at oleb.net>> wrote:
>> 
>>> On 17 Feb 2017, at 01:26, Ben Cohen via swift-evolution <swift-evolution at swift.org <mailto:swift-evolution at swift.org>> wrote:
>>> 
>>> Here is a list of commonly requested changes/enhancements to Dictionary, all of which would probably be appropriate to put together into a single evolution proposal:
>>> 
>>> init from/merge in a Sequence of Key/Value pairs (already raised as SE-100: https://github.com/apple/swift-evolution/blob/master/proposals/0100-add-sequence-based-init-and-merge-to-dictionary.md <https://github.com/apple/swift-evolution/blob/master/proposals/0100-add-sequence-based-init-and-merge-to-dictionary.md>).
>>> make the Values view collection a MutableCollection (as in this PR: https://github.com/apple/swift-evolution/pull/555 <https://github.com/apple/swift-evolution/pull/555>).
>>> Add a defaulting subscript get (e.g. counts[key, default: 0] += 1 or grouped(key, default:[]].append(value)).
>>> Add a group by-like init to create a Dictionary<K,[V]> from a sequence of V and a closure (V)->K.
>> Out of interest, how would you implement this? Does it require a generics feature that's slated for Swift 4? I tried two approaches that don't compile in a current Swift 3.1 snapshot (and I'm getting a segfault with both examples in a dev snapshot from 2017-02-14):
>> 
>> 1)
>> 
>> extension Dictionary {
>>     // error: same-type constraint 'Value' == '[S.Iterator.Element]' is recursive
>>     init<S: Sequence>(values: S, groupedBy: (S.Iterator.Element) -> Key)
>>         where Value == [S.Iterator.Element] {
>>         ...
>>         }
>>     }
>> }
>> 
>> 2)
>> 
>> // error: reference to generic type 'Array' requires arguments in <...>
>> extension Dictionary where Value == Array {
>>     init<S: Sequence>(values: S, groupedBy: (S.Iterator.Element) -> Key)
>>         where S.Iterator.Element == Value.Element {
>>         ...
>>         }
>>     }
>> }

I don't totally have my head around this, but won't a Dictionary initializer like this require parameterized extensions as described in the generics manifesto? 
	https://github.com/apple/swift/blob/master/docs/GenericsManifesto.md#parameterized-extensions

Something like this:

extension Dictionary<T> where Value == [T] {
    init<S: Sequence>(_ values: S, groupedBy: (S.Iterator.Element) -> Key) 
        where S.Iterator.Element == T 
    { ... }
}

For what it's worth, I had been expecting that we'd add this as a method on Sequence, a la joined(by:), not an initializer.

extension Sequence {
    func grouped<Key: Hashable>(by grouping: (Iterator.Element) -> Key) 
        -> [Key: [Iterator.Element]] 
    { ... }
}
let d = (1...10).grouped(by: { $0 % 3 })
// [2: [2, 5, 8], 0: [3, 6, 9], 1: [1, 4, 7, 10]]

Nate

> Oops, looks like a bug in the same-type constraint implementation. Ought to work in 3.1. Minimal crasher repro:
> 
> extension Array {
>   func f<S: Sequence>() 
>   where Element == S.Iterator.Element? {
>         
>   } 
> }
> 
> I’ve raised https://bugs.swift.org/browse/SR-4008 <https://bugs.swift.org/browse/SR-4008>
> 
> It ought to be done with the first one. For the second, you can’t constrain Value == Array because Array isn’t a type, needs to be Array<Something>.
> 
> As an (impractical) workaround, this compiles:
> 
> extension Dictionary {
>     subscript(k: Key, default default: Value) -> Value {
>         get { return self[k] ?? `default` }
>         set { self[k] = newValue }
>     }
> }
> 
> extension Dictionary where Value: RangeReplaceableCollection {
>     init<S: Sequence>(grouping values: S, by: (S.Iterator.Element) -> Key)
>         where S.Iterator.Element == Value.Iterator.Element {
>             self = [:]
>             for x in values {
>                 let k = by(x)
>                 self[k, default: Value()].append(x)
>             }
>     }
> }
> 
> 
> let s = [10,20,22,30,31]
> // have to explicitly type the Dictionary as a specific RRC
> let d: [Int:[Int]] = Dictionary(grouping: s) { $0%10 }
> 
> print(d)
> 
> 
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org <mailto:swift-evolution at swift.org>
> https://lists.swift.org/mailman/listinfo/swift-evolution <https://lists.swift.org/mailman/listinfo/swift-evolution>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20170219/0af3cbe1/attachment.html>


More information about the swift-evolution mailing list