217 Adaptive Text Editor

Description

Mbote Rubyists,

Sometimes the auto-completion features of text editors leave much to be desired. I’ve dreamed of a day when editors could successfully anticipate my actions to a high degree of accuracy.

This week’s quiz is to create an auto-completion module that will scan a corpus of text and use it to generate an auto-completion list. The adaptive part comes in where the most chosen auto-completion options appear first and the least used eventually drop off the list. Additionally if the text that is scanned was part of a project written by the user then the editor will be adapting the the user in that way as well.

It is not necessary to write an entire editor for the quiz. The simplest solution would be something like a class that can be initialized on a collection of files or text and have an autocomplete method that takes the most recently typed letters as a parameter. The method could also have optional parameters, such as a context, to be used to enhance the accuracy of the suggestions. Some contexts that would be most useful would be inside a a class or inside a method body. It could even get fancier by having the specific class that it is called in passed as an option as well, so as to suggest methods in that class higher than other methods.

As always you can embellish as much or as little as you wish. All solutions are welcome.

Have Fun!

Summary

This week’s quiz was solved by Martin Boese. Martin’s solution is simple and easy to understand (two of the most difficult features to achieve in coding!) so let’s dive in.

Martin’s solution creates a dictionary of words and store the count for each word as the learning step.

def learn(data)
  @words ||= {}
  data.split(' ').each do |word|
    w =  word.downcase.gsub(/[\,\.\(\)]/, '')
    @words[w] ||= 0
    @words[w] += 1
  end
end

The data paremeter is a string of text. The data is split on spaces and the frequency of each occurrence is tracked. Each word is made lowercase and some additional punctuation characters are removed.

The autocomplete method takes a word parameter, which is the prefix to complete, as well as an option choices parameter which decides how many choices to present.

def autocomplete(word, choices = 1)
  @words.find_all do |k,v|
    k =~ Regexp.new("^#{word.downcase}")
  end.sort { |a,b| b[1] <=> a[1] }.map { |e| e[0] }[0..choices-1]
end

Martin uses a Regexp to find all the entries that begin with the word and returns them sorted by the frequency count, so that more frequently used words will appear first.

Martin’s solution also provides us with some testing. Using the text of the quiz description the autocompleter is tested with several different prefixes. Here is the output for ‘a’:

Autocomplete on a --> ["a", "as", "an", "auto-completion", "and", "accuracy", "additionally", "anticipate", "actions", "adaptive"]

Good stuff!

Thank you Martin for your solution to this week’s quiz!


Saturday, August 08, 2009