Skip to content

Commit

Permalink
Merge pull request #140 from apple/fix-OrderedDictionary-grouping-inf…
Browse files Browse the repository at this point in the history
…erence

[OrderedDictionary] Fix type inference issue with `OrderedDictionary.init(grouping:by:)`
  • Loading branch information
lorentey authored Feb 9, 2022
2 parents 4825482 + 50e6a1a commit 20e7fce
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,50 @@ extension OrderedDictionary {
public init<S: Sequence>(
grouping values: S,
by keyForValue: (S.Element) throws -> Key
) rethrows where Value: RangeReplaceableCollection, Value.Element == S.Element {
try self.init(_grouping: values, by: keyForValue)
}

/// Creates a new dictionary whose keys are the groupings returned by the
/// given closure and whose values are arrays of the elements that returned
/// each key.
///
/// The arrays 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 an array of names, and then creates a
/// dictionary from that array by grouping the names by first letter:
///
/// let students = ["Kofi", "Abena", "Efua", "Kweku", "Akosua"]
/// let studentsByLetter = OrderedDictionary(grouping: students, by: { $0.first! })
/// // ["K": ["Kofi", "Kweku"], "A": ["Abena", "Akosua"], "E": ["Efua"]]
///
/// The new `studentsByLetter` dictionary has three entries, with students'
/// names grouped by the keys `"E"`, `"K"`, and `"A"`.
///
/// - Parameters:
/// - values: A sequence of values to group into a dictionary.
/// - keyForValue: A closure that returns a key for each element in
/// `values`.
///
/// - Complexity: Expected O(*n*) on average, where *n* is the count of
/// values, if `Key` implements high-quality hashing.
@inlinable
public init<S: Sequence>(
grouping values: S,
by keyForValue: (S.Element) throws -> Key
) rethrows where Value == [S.Element] {
// Note: this extra overload is necessary to make type inference work
// for the `Value` type -- we want it to default to `[S.Element`].
// (https://github.com/apple/swift-collections/issues/139)
try self.init(_grouping: values, by: keyForValue)
}

@inlinable
internal init<S: Sequence>(
_grouping values: S,
by keyForValue: (S.Element) throws -> Key
) rethrows where Value: RangeReplaceableCollection, Value.Element == S.Element {
self.init()
for value in values {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,14 +123,40 @@ class OrderedDictionaryTests: CollectionTestCase {
"one", "two", "three", "four", "five",
"six", "seven", "eight", "nine", "ten"
]
let d = OrderedDictionary<Int, [String]>(grouping: items, by: { $0.count })
let d = OrderedDictionary<Int, ContiguousArray<String>>(
grouping: items, by: { $0.count })
expectEqualElements(d, [
(key: 3, value: ["one", "two", "six", "ten"]),
(key: 5, value: ["three", "seven", "eight"]),
(key: 4, value: ["four", "five", "nine"]),
])
] as [(key: Int, value: ContiguousArray<String>)])
}

func test_grouping_initializer_inference() {
struct StatEvent: Equatable {
var name: String
var date: String
var hours: Int
}

let statEvents = [
StatEvent(name: "lunch", date: "01-01-2015", hours: 1),
StatEvent(name: "dinner", date: "01-01-2015", hours: 1),
StatEvent(name: "dinner", date: "01-01-2015", hours: 1),
StatEvent(name: "lunch", date: "01-01-2015", hours: 1),
StatEvent(name: "dinner", date: "01-01-2015", hours: 1)
]

// We expect this to be inferred to `OrderedDictionary<String, [StatEvent]>`
let d = OrderedDictionary(grouping: statEvents, by: { $0.name })
let expected = [
(key: "lunch", value: [statEvents[0], statEvents[3]]),
(key: "dinner", value: [statEvents[1], statEvents[2], statEvents[4]]),
]
expectEqualElements(d, expected)
}


func test_uncheckedUniqueKeysWithValues_labeled_tuples() {
let items: KeyValuePairs<String, Int> = [
"zero": 0,
Expand Down

0 comments on commit 20e7fce

Please sign in to comment.