9
9
//
10
10
//===----------------------------------------------------------------------===//
11
11
12
+ public struct KeysAreNotUnique < Key, Element> : Error {
13
+ public let key : Key
14
+ public let previousElement : Element
15
+ public let conflictingElement : Element
16
+
17
+ @inlinable
18
+ public init ( key: Key , previousElement: Element , conflictingElement: Element ) {
19
+ self . key = key
20
+ self . previousElement = previousElement
21
+ self . conflictingElement = conflictingElement
22
+ }
23
+ }
24
+
12
25
extension Sequence {
26
+ /// Creates a new Dictionary from the elements of `self`, keyed by the
27
+ /// results returned by the given `keyForValue` closure. Deriving the
28
+ /// same duplicate key for more than one element of `self` will cause
29
+ /// an error to be thrown.
30
+ ///
31
+ /// - Parameters:
32
+ /// - keyForValue: A closure that returns a key for each element in `self`.
33
+ /// - Throws: `KeysAreNotUnique ` if two values map to the same key (via `keyForValue`).
34
+ @inlinable
35
+ public func keyed< Key> (
36
+ by keyForValue: ( Element ) throws -> Key
37
+ ) throws -> [ Key : Element ] {
38
+ var result = [ Key: Element] ( )
39
+
40
+ for element in self {
41
+ let key = try keyForValue ( element)
42
+
43
+ if let previousElement = result. updateValue ( element, forKey: key) {
44
+ throw KeysAreNotUnique ( key: key, previousElement: previousElement, conflictingElement: element)
45
+ }
46
+ }
47
+
48
+ return result
49
+ }
50
+
13
51
/// Creates a new Dictionary from the elements of `self`, keyed by the
14
52
/// results returned by the given `keyForValue` closure. As the dictionary is
15
53
/// built, the initializer calls the `combine` closure with the current and
@@ -18,50 +56,30 @@ extension Sequence {
18
56
/// choose between the two values, combine them to produce a new value, or
19
57
/// even throw an error.
20
58
///
21
- /// If no `combine` closure is provided, deriving the same duplicate key for
22
- /// more than one element of self results in a runtime error.
23
- ///
24
59
/// - Parameters:
25
- /// - keyForValue: A closure that returns a key for each element in
26
- /// `self`.
60
+ /// - keyForValue: A closure that returns a key for each element in `self`.
27
61
/// - combine: A closure that is called with the values for any duplicate
28
62
/// keys that are encountered. The closure returns the desired value for
29
63
/// the final dictionary.
30
64
@inlinable
31
65
public func keyed< Key> (
32
66
by keyForValue: ( Element ) throws -> Key ,
33
- uniquingKeysWith combine: ( ( Key , Element , Element ) throws -> Element ) ? = nil
67
+ uniquingKeysWith combine: ( Key , Element , Element ) throws -> Element
34
68
) rethrows -> [ Key : Element ] {
35
69
var result = [ Key: Element] ( )
36
70
37
- if combine != nil {
38
- // We have a `combine` closure. Use it to resolve duplicate keys.
39
-
40
- for element in self {
41
- let key = try keyForValue ( element)
42
-
43
- if let oldValue = result. updateValue ( element, forKey: key) {
44
- // Can't use a conditional binding to unwrap this, because the newly bound variable
45
- // doesn't play nice with the `rethrows` system.
46
- let valueToKeep = try combine!( key, oldValue, element)
47
-
48
- // This causes a second look-up for the same key. The standard library can avoid that
49
- // by calling `mutatingFind` to get access to the bucket where the value will end up,
50
- // and updating in place.
51
- // Swift Algorithms doesn't have access to that API, so we make due.
52
- // When this gets merged into the standard library, we should optimize this.
53
- result [ key] = valueToKeep
54
- }
55
- }
56
- } else {
57
- // There's no `combine` closure. Duplicate keys are disallowed.
71
+ for element in self {
72
+ let key = try keyForValue ( element)
58
73
59
- for element in self {
60
- let key = try keyForValue ( element)
74
+ if let oldValue = result . updateValue ( element, forKey : key ) {
75
+ let valueToKeep = try combine ( key , oldValue , element)
61
76
62
- guard result. updateValue ( element, forKey: key) == nil else {
63
- fatalError ( " Duplicate values for key: ' \( key) ' " )
64
- }
77
+ // This causes a second look-up for the same key. The standard library can avoid that
78
+ // by calling `mutatingFind` to get access to the bucket where the value will end up,
79
+ // and updating in place.
80
+ // Swift Algorithms doesn't have access to that API, so we make due.
81
+ // When this gets merged into the standard library, we should optimize this.
82
+ result [ key] = valueToKeep
65
83
}
66
84
}
67
85
0 commit comments