Practice II. Foobar surrounder

— imperative and functional style

2021-07-07

Since I don’t use functional programming at work, I tend to have an “aesthetic” style when writing JavaScript functional style. Performance has never been an issue in my small, JavaScript hobby projects so far.

To remind me that functional programming using JavaScript often produce poor performance if you don’t make performance a parameter to consider, I made two versions of the same problem: surrounding the most frequent word in a text with ‘foo’ and ‘bar’.

Both solutions could be improved, but in relative terms I find my functional solution more elegant. But the performance is quite bad. I've exluded loremIpsum, a very long string (92208 words) containing the 'lorem ipsum'-text.

Functional style

const loremIpsum = require("./lorem-ipsum.js");

const countWord = (words, word) => {
  const lowerCaseWord = word.toLowerCase();
  if (lowerCaseWord in words) {
    words[lowerCaseWord] = words[lowerCaseWord] + 1;
  } else {
    words[lowerCaseWord] = 1;
  }
  return words;
};

const isNotEmpty = (word) => word !== "";

const countWords = (string) =>
  string
    .split(/[ ,;!?.'"\t\n]+/)
    .filter(isNotEmpty)
    .reduce(countWord, {});
    
const compareWordLength = ([_, v1], [__, v2]) => v2 - v1;

const sortWordList = (wordList) =>
  Object.entries(wordList).sort(compareWordLength);

const head = (ws) => ws[0];

const getNWords = (n) => (li) => li.slice(0, n).map(head);

const surroundWord = (before, after) => (word) => `${before}${word}${after}`;

const surroundWordInText = (before, after, str) => (word) => {
  const wordRegEx = new RegExp(word, "gi");
  return str.replace(wordRegEx, surroundWord(before, after));
};

const compose = (...fns) => (initial) =>
  fns.reduceRight((a, b) => b(a), initial);

const result = compose(
  surroundWordInText("foo", "bar", loremIpsum),
  head,
  getNWords(1),
  sortWordList,
  countWords
)(loremIpsum);
console.log(result);

Results

I’ve not made a systematic benchmark; these results are to some extent therefore unreliable. For measurements I’ve used the Linux utility time:

Imperative version
real    0m0.096s
user    0m0.083s
sys     0m0.017s


Fp version
real    0m6.334s
user    0m6.353s
sys     0m0.081s

About | Archive