Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Word Count in Swift [closed]

What is a more elegant way of writing a simple word count function in Swift?

//Returns a dictionary of words and frequency they occur in the string
func wordCount(s: String) -> Dictionary<String, Int> {
    var words = s.componentsSeparatedByString(" ")
    var wordDictionary = Dictionary<String, Int>()
    for word in words {
        if wordDictionary[word] == nil {
            wordDictionary[word] = 1
        } else {
            wordDictionary.updateValue(wordDictionary[word]! + 1, forKey: word)
        }
    }
    return wordDictionary
}

wordCount("foo foo foo bar")
// Returns => ["foo": 3, "bar": 1]
like image 917
mmla Avatar asked Jun 08 '14 23:06

mmla


2 Answers

Your method was pretty solid, but this makes a couple improvements. I store the value count using Swifts "if let" keyword to check for an optional value. Then I can use count when updating the dictionary. I used the shorthand notation for updateValue (dict[key] = val). I also split the original string on all whitespace instead of just a single space.

func wordCount(s: String) -> Dictionary<String, Int> {
    var words = s.componentsSeparatedByCharactersInSet(NSCharacterSet.whitespaceCharacterSet())
    var wordDictionary = Dictionary<String, Int>()
    for word in words {
        if let count = wordDictionary[word] {
            wordDictionary[word] = count + 1
        } else {
            wordDictionary[word] = 1
        }
    }
    return wordDictionary
}
like image 161
Dash Avatar answered Nov 15 '22 08:11

Dash


I don't think this is more elegant because the readability is terrible and it requires and extension on Dictionary but it was really fun to write and shows you the potential power of swift:

extension Dictionary {
    func merge(with other: [KeyType:ValueType], by merge: (ValueType, ValueType) -> ValueType) -> [KeyType:ValueType] {
        var returnDict = self
        for (key, value) in other {
            var newValue = returnDict[key] ? merge(returnDict[key]!, value) : value
            returnDict.updateValue(newValue, forKey: key)
        }
        return returnDict
    }
}

func wordCount(s: String) -> [String:Int] {
    return s.componentsSeparatedByString(" ").map {
        [$0: 1]
    }.reduce([:]) {
        $0.merge(with: $1, +)
    }
}
wordCount("foo foo foo bar")

I do think that merge extension would be useful in other circumstances though

like image 36
drewag Avatar answered Nov 15 '22 06:11

drewag