Repository: gchq/CyberChef
File: src/core/operations/RAKE.mjs (JavaScript)

Code before:
                if (stopWords.includes(token)) {
                    // If token is stop word then split to create phrase
                    phrases.push(splitSent.slice(startIndex, i));
                    startIndex = i + 1;
                } else {
                    // If token is not a stop word add to the count of the list of words
                    if (tokens.includes(token)) {
                        wordFrequencies[tokens.indexOf(token)]+=1;
                    } else {
                        tokens.push(token);
                        wordFrequencies.push(1);
                    }
                }
            }
            phrases.push(splitSent.slice(startIndex));
        }

        // remove empty phrases
        phrases = phrases.filter(subArray => subArray.length > 0);

        // Remove duplicate phrases
        phrases = phrases.unique();
        
        // Generate word_degree_matrix and populate
        const wordDegreeMatrix = Array(tokens.length).fill().map(() => Array(tokens.length).fill(0));
        for (let p=0; p < phrases.length; p++) {
            for (let w1=0; w1 < phrases[p].length; w1++) {
                for (let w2=0; w2 < phrases[p].length; w2++) {
                    wordDegreeMatrix[tokens.indexOf(phrases[p][w1])][tokens.indexOf(phrases[p][w2])]++;
                }
            }
        }

        // Calculate degree score for each token
        const degreeScores = Array(tokens.length).fill(0);
        for (let i=0; i<tokens.length; i++) {
            let wordDegree = 0;
            for (let j=0; j<wordDegreeMatrix.length; j++) {
                wordDegree += wordDegreeMatrix[j][i];
            }
            degreeScores[i] = wordDegree / wordFrequencies[i];
        }

        // Calculate score for each phrase
        const scores = phrases.map(function (phrase) {
            let score = 0;
            phrase.forEach(function (token) {
                score += degreeScores[tokens.indexOf(token)];
            });
            return new Array(score, phrase.join(" "));
        });

Review comment (performance):
You can improve the readability of this by using 'for of' loops instead of dealing with index loops:

```
for (let phrase of phrases) {
  for (let word1 of phrase) {
    for (let word2 of phrase) {
      wordDegreeMatrix[tokens.indexOf(word1)][tokens.indexOf(word2)]++;
    }
  }
}
```

This is the best of both worlds, the improved readability of `forEach` without sacrificing the 50% reduction in performance.

Code after:
                if (stopWords.includes(token)) {
                    // If token is stop word then split to create phrase
                    phrases.push(splitSent.slice(startIndex, i));
                    startIndex = i + 1;
                } else {
                    // If token is not a stop word add to the count of the list of words
                    if (tokens.includes(token)) {
                        wordFrequencies[tokens.indexOf(token)]+=1;
                    } else {
                        tokens.push(token);
                        wordFrequencies.push(1);
                    }
                }
            }
            phrases.push(splitSent.slice(startIndex));
        }

        // remove empty phrases
        phrases = phrases.filter(subArray => subArray.length > 0);

        // Remove duplicate phrases
        phrases = phrases.unique();
        
        // Generate word_degree_matrix and populate
        const wordDegreeMatrix = Array(tokens.length).fill().map(() => Array(tokens.length).fill(0));
        for (const phrase of phrases) {
            for (const word1 of phrase) {
                for (const word2 of phrase) {
                    wordDegreeMatrix[tokens.indexOf(word1)][tokens.indexOf(word2)]++;
                }
            }
        }

        // Calculate degree score for each token
        const degreeScores = Array(tokens.length).fill(0);
        for (let i=0; i<tokens.length; i++) {
            let wordDegree = 0;
            for (let j=0; j<wordDegreeMatrix.length; j++) {
                wordDegree += wordDegreeMatrix[j][i];
            }
            degreeScores[i] = wordDegree / wordFrequencies[i];
        }

        // Calculate score for each phrase
        const scores = phrases.map(function (phrase) {
            let score = 0;
            phrase.forEach(function (token) {
                score += degreeScores[tokens.indexOf(token)];
            });
            return new Array(score, phrase.join(" "));
        });