-4

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.

Dávid Pásztor
  • 51,403
  • 9
  • 85
  • 116
  • https://stackoverflow.com/questions/6171422/objective-c-nsstring-wordcount (should be easily translated into Swift) + `CountedSet`? But should "is" and "are" be counted as the same word "be/to be"? – Larme Sep 06 '17 at 13:28
  • 2
    I'm guessing that your question is being down-voted because it doesn't seem like you've actually tried to find solutions for this yourself. There is already a lot of material available, such as that linked to you by @Larme. Please don't expect others to do your work for you. – Guy Kogus Sep 06 '17 at 13:32
  • Of course I do not expect you to write code for me. I am new for Swift. I expect that maybe you can suggest for me about its logic. For example "you can use this method or this logic. Or firstly you must detect the words or count etc.". After your suggest I want to create my codes correctly. I wanted to use your experiences about your simple! problem. But if you can not help me without any codes I didn't write, I understand. Thank you again. – Ismail Caferoglu Sep 06 '17 at 14:01

2 Answers2

1

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

Community
  • 1
  • 1
Dávid Pásztor
  • 51,403
  • 9
  • 85
  • 116
0

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]
Alain T.
  • 40,517
  • 4
  • 31
  • 51