The mathematical name for what you're looking for (the most frequent element in a collection) is called the mode. There could be ties (e.g. [1, 1, 2, 2, 3, 3]
has 3 modes: [1, 2, 3]
)
If you want any one of the modes (not caring which ones, specifically), you can use Dictionary.max(by:)
, which you can use to find the (element, count) pair with the highest count (which is the dict value). Then, you can get the key of this pair, which will be the mode element.
extension Sequence where Element: Hashable {
func countOccurrences() -> [Element: Int] {
return self.reduce(into: [:]) { (occurences, element) in occurences[element, default: 0] += 1}
}
func mode() -> Element? {
return self.countOccurrences()
.max(by: { $0.value < $1.value })?
.key
}
func modes() -> [Element] {
var firstModeNumOccurences: Int? = nil
let modes = countOccurrences()
.sorted { pairA, pairB in pairA.value > pairB.value } // sorting in descending order of num occurences
.lazy
.prefix(while:) { (_, numOccurences) in
if firstModeNumOccurences == nil { firstModeNumOccurences = numOccurences }
return numOccurences == firstModeNumOccurences
}
.map { (element, _) in element }
return Array(modes)
}
}
print([1, 2, 3, 3, 4, 4].mode() as Any) // => 3 or 4, non-deterministic
print([1, 2, 3, 3, 4, 4].modes() as Any) // => [3, 4]