I am iterating over some strings I get from my server. I need to know which 25 of the strings occur the most. I was wondering what the most efficient / fastest way of doing that can me. I could get anywhere from 1000 to 10000 strings. I was thinking of an approach where I make a map of string to occurrence. Then make a list of the occurrences. Sort that list. Then iterate over the (key,value)
s in the map and find the ones corresponding to those highest numbers. Sounds a bit convoluted so thought I would ask to see if anyone has a better approach. Everything I found online is pretty similar to what I was thinking.
Asked
Active
Viewed 73 times
0

TurtleFan
- 289
- 2
- 17
-
1you can use an NSCountedSet to keep the tally. You will still need to iterate the set to build the list of top 25 – Paulw11 Nov 10 '15 at 08:53
2 Answers
2
This is a perfect use case for Cocoa's CountedSet
(Apple Dev Doc).
Example provided by hackingwithswift.com
let set = NSCountedSet()
set.addObject("Bob")
set.addObject("Charlotte")
...
set.addObject("Bob")
print(set.countForObject("Bob")) // prints 2
Now you are able to sort your dict with build in sort()
methods. For example please have a look at this related stack overflow thread.
Update
A possible method to sort is:
set.sort { return set.countForObject($0) < set.countForObject($1) }
-
Hi how can I sort it with the built in methods? I can't seem to call `set.sort()` – TurtleFan Nov 10 '15 at 09:10
-
-
I used my Playground to evaluated the posted source. Sorry if I made a mistake or I waved to a false friend. – Tobonaut Nov 10 '15 at 14:59
1
This is a pretty common pattern. In AWK, the text processing language, it was so common that the implementation was absurdly simple: stringCount[newString]++
.
In Swift, we need to be a bit more explicit - Playground code using pure Swift:
var stringCount: [String: Int] = [:] // i.e. a Dictionary keyed by the strings, whose value is the occurrence count
func addString(newString: String) {
if let oldCount = stringCount[newString] { // We have seen this string before
stringCount[newString] = oldCount + 1
} else { // It's the first time we've seen this one
stringCount[newString] = 1
}
}
addString("Grimxn")
addString("TurtleFan")
addString("Grimxn")
addString("Grimxn")
addString("TurtleFan")
addString("Stack Overflow")
stringCount // ["Grimxn": 3, "TurtleFan": 2, "Stack Overflow": 1]
Or, as @Paulw11 points out, you could use Cocoa's NSCountedSet
:
var stringCount2 = NSCountedSet()
stringCount2.addObject("Grimxn")
stringCount2.addObject("TurtleFan")
stringCount2.addObject("Grimxn")
stringCount2.addObject("Grimxn")
stringCount2.addObject("TurtleFan")
stringCount2.addObject("Stack Overflow")
let counts = stringCount2.map( { return ($0, stringCount2.countForObject($0)) } )
counts // [(.0 "TurtleFan", .1 2), (.0 "Stack Overflow", .1 1), (.0 "Grimxn", .1 3)]

Grimxn
- 22,115
- 10
- 72
- 85