I want to find and sort by quantity the most passed 3 words in my UITextView.
For example:
"good good good very very good good. bad bad unfortunately bad."
It must do that:
good (5 times) bad (3 times) very (2 times)
How can I do this? Thanks.
I want to find and sort by quantity the most passed 3 words in my UITextView.
For example:
"good good good very very good good. bad bad unfortunately bad."
It must do that:
good (5 times) bad (3 times) very (2 times)
How can I do this? Thanks.
You can use String.components(separatedBy:)
to get the words of textView.text
, then you can use an NSCountedSet
to get the count of each word.
You can of course tweak the separator characters used as an input to components(separatedBy:)
to meet your exact criteria.
let textViewText = "good good good very very good good. bad bad unfortunately bad."
//separate the text into words and get rid of the "" results
let words = textViewText.components(separatedBy: [" ","."]).filter({ !$0.isEmpty })
//count the occurrence of each word
let wordCounts = NSCountedSet(array: words)
//sort the words by their counts in a descending order, then take the first three elements
let sortedWords = wordCounts.allObjects.sorted(by: {wordCounts.count(for: $0) > wordCounts.count(for: $1)})[0..<3]
for word in sortedWords {
print("\(word) \(wordCounts.count(for: word))times")
}
Output:
good 5times
bad 3times
very 2times
Here's a one liner that will give you the top 3 words in order of frequency:
let words = "good good good very very good good. bad bad unfortunately bad"
let top3words = Set(words.components(separatedBy:" "))
.map{($0,words.components(separatedBy:$0).count-1)}
.sorted{$0.1 > $01.1}[0..<3]
print(top3words) // [("good", 5), ("bad", 3), ("very", 2)]
It creates a set with each distinct words and then maps each of them with the count of occurrences in the string (words). Finally it sorts the (word,count) tuples on the count and returns the first 3 elements.
[EDIT] the only issues with the above method is that, although it works with your example string, it assumes that no word is contained in another and that they are only separated by spaces.
To do a proper job, the words must first be isolated in an array eliminating any special characters (i.e. non-letters). It may also be appropriate to ignore upper and lower case but you didn't specify that and I dint't want to add to the complexity.
Here's how the same approach would be used on an array of words (produced from the same string):
let wordList = words.components(separatedBy:CharacterSet.letters.inverted)
.filter{!$0.isEmpty}
let top3words = Set(wordList)
.map{ word in (word, wordList.filter{$0==word}.count) }
.sorted{$0.1>$1.1}[0..<3]