I'm trying to create a Counter class in Swift like the collections.Counter class in Python, which works like this: collections.Counter() | HackerRank
Or, as a simple example:
>>> Counter("hello")
Counter({'h': 1, 'e': 1, 'l': 2, 'o': 1})
>>> Counter([1,2,3,2])
Counter({1: 1, 2: 2, 3:1})
Here's what I got in Swift:
import Foundation
struct Counter<T: Hashable>: CustomStringConvertible {
var description: String {
return dict.description
}
var dict: [T: Int] = [:]
init(_ val: String) {
for char in val {
self.dict[String(char), default: 0] += 1
}
}
init(_ val: Array<T>) {
for elem in val {
self.dict[elem, default: 0] += 1
}
}
func elements() -> [T] {
return Array(dict.keys)
}
mutating func clear() {
dict = [:]
}
}
The issue is it says, on the String init that
Cannot convert value of type 'String.Element' (aka 'Character') to expected argument type 'T'
This means that while this class works just like the Python one when implementing with arrays, it looks clunky with Strings. I can edit it so that:
init(_ val: String) {
for char in val {
self.dict[String(char) as! T, default: 0] += 1
}
}
But now, to use the Counter with a String, I must do:
// Without the <String>, it says "Generic parameter 'T' could not be inferred"
print(Counter<String>("hello"))
print(Counter([1,2,3,2]))
Is there a way to explicitly define T as a String in the init instead of during every usage, so that I can use Counter("hello")?