0

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.

TurtleFan
  • 289
  • 2
  • 17
  • 1
    you 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 Answers2

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) }

Community
  • 1
  • 1
Tobonaut
  • 2,245
  • 2
  • 26
  • 39
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