3
\$\begingroup\$

I've written a JavaScript dictionary sorting algorithm, which takes a .txt file (the dictionary), and loads it via node's file system. The purpose of this algorithm is to sort every word into its corresponding array based on its letter pattern. For example, the word little would have the letter pattern of ABCCDE, and hello would have the letter pattern of ABCCD. The purpose of this sorting algorithm is to use it to decode substitution ciphers; however, this is the only working code I've written so far for it. This code works, and I have a sorted dictionary file here.

However, I want to know how I might be able to improve this algorithm to make it as fast and efficient as possible. Even though its only run once, I want to get into the habit of writing efficient code.

To break down exactly what's going on in the algorithm I've added a few comments, but to elaborate it loads each word from the dictionary and stores it in an array, in which I then iterate through the array and each letter of the word. The clpl variable starts at 'A', and it checks if it exists in a temp object. If it does, it adds that letter to the letter pattern, if it does not, it creates a new property on the object and assigns it the current letter as a value. It adds the assigned letter to lp, which is initialized as an empty string.

The line clpl = String.fromCharCode(clpl.charCodeAt(0) + 1);gets the next letter. After it has iterated through each letter in the word, it checks if the current letter pattern exists in the sortedDictionary object, if it does it pushes it to an array containing all words with its letter pattern. If it does not, it creates a new array for that letter pattern and pushes the current word to that array. After it has gone through every word, it writes the sortedDictionary object to an external JSON file.

//load file system
var fs = require("fs");
//load jsonfile
var jsonfile = require("jsonfile");

//create var for dictionary file
var dictFile = "american-english", sortedDictFile = "sortedDictionary.json";

//empty object to hold sorted dictionary according to letter patterns
//empty dictionary array to hold words
var sortedDictionary = {}, dictionary = [];

//declare variables for use
var temp, clpl, lp, word;

console.time("Dictionary Sort");

fs.readFile(dictFile, "utf8", function(error, data){
    if(error) throw error;
    //push all words into an array 
    dictionary = data.toString().split("\n");

    for(var i = 0; i < dictionary.length; i++){
        //set word to current word in dictionary
        word = dictionary[i];
        //set temp to empty object, clpl to A, and lp to an empty string
        //this is used to get the current letter pattern
        temp = {}, clpl = 'A', lp = '';

        for(var j = 0; j < word.length; j++){
            if(word[j] in temp){
              lp += temp[word[j]];
            } else {
              temp[word[j]] = clpl;
              lp += clpl;
              clpl = String.fromCharCode(clpl.charCodeAt(0) + 1);
            }
        }

        //if letter pattern of word exists in sorted dictionary
        if(lp in sortedDictionary){
            //add word to the array of words with same letter pattern
            sortedDictionary[lp].push(word);
        } else {
            //if letter pattern is new, create new array to store words
            sortedDictionary[lp] = [];
            //add word to the array of words with same letter pattern
            sortedDictionary[lp].push(word);
        }
    }

    //write the sortedDictionary object to the sortedDictionary.json file
    jsonfile.writeFile(sortedDictFile, sortedDictionary, {spaces: 2}, function(error){
        if(error) throw error;
    });

    //time to sort and write to json file - Dictionary Sort: 687ms (137602 lines)
    console.timeEnd("Dictionary Sort");
});
\$\endgroup\$
1
\$\begingroup\$

This can be improved and shortened by naming the concepts you are using:

  • A function called encodeWord that takes a single word and returns its encoded value
  • A function called groupedByCodes which takes an array of words, and returns the object you are seeking: codes as keys, and arrays of words that get encoded to those keys.

This will have the following benefits:

  • What your code is doing will be crystal clear.
  • You'll have less code
  • Most of your temporary variables will vanish

I've also purposefully left out the writing and reading of the files, as that's really a separate concern from your main program.

Rewriting it this way, you'll get something that looks like this:

var sampleFile = "CAT\nDOG\nTOM\nBOB\nTOT",
    words = sampleFile.split("\n");

console.log(groupedByCodes(words));
// { ABC: [ 'CAT', 'DOG', 'TOM' ], ABA: [ 'BOB', 'TOT' ] }

function groupedByCodes(words) {
  return words.reduce(function(dict, word) {
    var code = encodeWord(word);
    if (!dict[code]) dict[code] = []; 
    dict[code].push(word);
    return dict;
  }, {});
}

function encodeWord(word) {
  var encodingDict = {}, nextCode = 65; //'A'
  return word.split('').map(encodeLetter).join('');

  function encodeLetter(l) {
    return encodingDict[l] || (encodingDict[l] = String.fromCharCode(nextCode++));
  }
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy