Guides/Grouped.md
Groups up elements of a sequence into a new Dictionary, whose values are Arrays of grouped elements, each keyed by the result of the given closure.
let fruits = ["Apricot", "Banana", "Apple", "Cherry", "Avocado", "Coconut"]
let fruitsByLetter = fruits.grouped(by: { $0.first! })
// Results in:
// [
// "B": ["Banana"],
// "A": ["Apricot", "Apple", "Avocado"],
// "C": ["Cherry", "Coconut"],
// ]
If you wish to achieve a similar effect but for single values (instead of Arrays of grouped values), see keyed(by:).
The grouped(by:) method is declared as a Sequence extension returning
[GroupKey: [Element]].
extension Sequence {
public func grouped<GroupKey>(
by keyForValue: (Element) throws -> GroupKey
) rethrows -> [GroupKey: [Element]]
}
Calling grouped(by:) is an O(n) operation.
| Language | Grouping API |
|---|---|
| Java | groupingBy |
| Kotlin | groupBy |
| C# | GroupBy |
| Rust | group_by |
| Ruby | group_by |
| Python | groupby |
| PHP (Laravel) | groupBy |
All the surveyed languages name this operation with a variant of "grouped" or "grouping". The past tense grouped(by:) best fits Swift's API Design Guidelines.
Java and C# are interesting in that they provide multiple overloads with several points of customization:
.transformValues { group in Set(group) } on the resultant dictionary, but avoiding the intermediate allocation of Arrays of each group..transformValues { group in group.map(someTransform) } on the resultant dictionary, but avoiding the intermediate allocation of Arrays of each group.OrderedDictionary, SortedDictionary or TreeDictionary instead of the default (hashed, unordered) Dictionary.grouped(by:). One could wrap the resultant dictionary in an initializer to one of the other dictionary types, but that isn't sufficient: Once the Dictionary loses the ordering, there's no way to get it back when constructing one of the ordered dictionary variants.It is not clear which of these points of customization are worth supporting, or what the best way to express them might be.