I'm new at generics, but I've written an array extension to group an array by array element into a two dimensional array:
extension Array {
func group<U: Hashable>(by key: (Element) -> U) -> [[Element]] {
//keeps track of what the integer index is per group item
var indexKeys = [U : Int]()
var grouped = [[Element]]()
for element in self {
let key = key(element)
if let ind = indexKeys[key] {
grouped[ind].append(element)
}
else {
grouped.append([element])
indexKeys[key] = grouped.count - 1
}
}
return grouped
}
}
For an array of this struct:
struct Thing {
var category: String
var name: String
}
I want to be able to group an array of things [Thing]
into a two dimensional array [[Thing]]
based on Thing.category.
I use the extension like this:
let things = [
Thing(category: "A", name: "Apple"),
Thing(category: "B", name: "Boy"),
Thing(category: "A", name: "Alligator"),
Thing(category: "B", name: "Ball"),
Thing(category: "B", name: "Billboard")
]
let groupedThings = things.group { $0.category }
This returns something like:
//groupedThings
[
[
Thing(category: "A", name: "Apple"),
Thing(category: "A", name: "Alligator")
],
[
Thing(category: "B", name: "Boy"),
Thing(category: "B", name: "Ball"),
Thing(category: "B", name: "Billboard")
]
]
Please note that I'm not concerned about sort order.
How does my extension look? Since I'm fairly new at this, I'd like to know if I'm over-complicating it. Is there a way to write the extension more concisely? What about speed issues?