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