Continuing the discussion from Tip: Doing more than two partitions for a Sequence (or Collection):
Instead of using the Sequence
extension method given in the previous thread, I wanted to move it to a variant initializer on Dictionary
.
extension Dictionary {
public init<S: Sequence>(grouping values: __owned S, as type: Value.Type, by keyForValue: (Value.Element) throws -> Key) rethrows where Value: RangeReplaceableCollection, S.Element == Value.Element {
self = try Dictionary(grouping: values, by: keyForValue).mapValues({ Value($0) })
}
}
but kept getting an error on the predicate. I tried another approach:
extension Dictionary where Value: RangeReplaceableCollection {
/// Creates a new dictionary whose keys are the groupings returned by the
/// given closure and whose values are collections of the elements, using a
/// given type, that returned each key.
///
/// The collections in the "values" position of the new dictionary each
/// contain at least one element, with the elements in the same order as the
/// source sequence.
///
/// The following example declares a string, then creates a dictionary from
/// that string by grouping by a filtering predicate.
///
/// let vowels = Set<Character> = ["a", "e", "i", "o", "u"]
/// let swiftMessage = "Swift Dictionary"
/// let swiftMsgByType = Dictionary(grouping: swiftMessage, as: String.self, by: { vowels.contains($0) })
/// // [false: "Swft Dctnry", true: "iiioa"]
///
/// The new `swiftMsgByType` dictionary has two entries, one grouping
/// non-vowels (key `false`) and one group with vowels (key `true`).
///
/// - Parameters:
/// - values: A sequence of values to group into a dictionary.
/// - type: A metatype specifier for the per-key collection type of
/// elements.
/// - keyForValue: A closure that returns a key for each element in
/// `values`.
@inlinable
public init<S: Sequence>(grouping values: S, as type: Value.Type, by keyForValue: (S.Element) throws -> Key) rethrows where S.Element == Value.Element {
let arrayedDictionary = try Dictionary(grouping: values, by: keyForValue)
self = arrayedDictionary.mapValues(Value.init)
}
}
The error occurs on the first line, highlighting "keyForValue". The error is:
Cannot convert value of type '(Value.Element) throws -> Key' to expected argument type '(_) throws -> _'
The fix-it is a non-sensical
Insert ' as! (_) throws -> _'
(Using the fix gives an "Expected type" error.) The code seems like it should work, since Value.Element
and S.Element
must be the same. Is there a compiler bug in recognizing transitive closure signatures in initializers? From the other post, the code works just fine outside an initializer.