Skip to content

Instantly share code, notes, and snippets.

@im-jersh
Last active April 20, 2017 17:37
Show Gist options
  • Select an option

  • Save im-jersh/6be7e5bd62a0ec377dce8c5e8c35b6d7 to your computer and use it in GitHub Desktop.

Select an option

Save im-jersh/6be7e5bd62a0ec377dce8c5e8c35b6d7 to your computer and use it in GitHub Desktop.
Group elements of array by some property
import Foundation
internal protocol Groupable {
associatedtype GroupingType : Hashable
var groupingKey : GroupingType? { get }
}
extension Array where Element : Groupable {
typealias GroupingType = Element.GroupingType
func grouped(nilsAsSingleGroup nilsAsSingleGroup: Bool = false) -> [[Element]] {
var groups = [Int : [Element]]()
var groupsOrder = [Int]()
let nilGroupingKey = UUID().uuidString.hashValue
var nilGroup = [Element]()
for element in self {
// If it has a grouping key then use it. Otherwise, conditionally make one based on if nils get put in the same bucket or not
var groupingKey = element.groupingKey?.hashValue ?? UUID().uuidString.hashValue
if nilsAsSingleGroup, element.groupingKey == nil { groupingKey = nilGroupingKey }
// Group nils together
if nilsAsSingleGroup, element.groupingKey == nil {
nilGroup.append(element)
continue
}
// Place the element in the right bucket
if let _ = groups[groupingKey] {
groups[groupingKey]!.append(element)
} else {
// New key, track it
groups[groupingKey] = [element]
groupsOrder.append(groupingKey)
}
}
// Build our array of arrays from the dictionary of buckets
var grouped = groupsOrder.flatMap{ groups[$0] }
if nilsAsSingleGroup, !nilGroup.isEmpty { grouped.append(nilGroup) }
return grouped
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment