4
\$\begingroup\$

I wanted to practice functional programming (fp) without using any library but using vanilla JS only. So I took a problem from Advent of Code (the 1st part of Day 4):

A new system policy has been put in place that requires all accounts to use a passphrase instead of simply a password. A passphrase consists of a series of words (lowercase letters) separated by spaces.

To ensure security, a valid passphrase must contain no duplicate words.

For example:

aa bb cc dd ee is valid.

aa bb cc dd aa is not valid - the word aa appears more than once.

aa bb cc dd aaa is valid - aa and aaa count as different words.

The system's full passphrase list is available as your puzzle input. How many passphrases are valid?

My solution in FP:

const INPUT =
`pphsv ojtou brvhsj cer ntfhlra udeh ccgtyzc zoyzmh jum lugbnk
vxjnf fzqitnj uyfck blnl impo kxoow nngd worcm bdesehw
...
caibh nfuk kfnu llfdbz uxjty yxjut jcea`;

const get = input => input.split('\n');
const countDuplicate = words => words.reduce((acc, word) => {
  return Object.assign(acc, {[word]: (acc[word] || 0) + 1});
}, {});
const onlyUniqueWords = phrases => {
  const words = phrases.split(' ');
  const duplicateWords = countDuplicate(words);
  return !Object.values(duplicateWords).some(w => w > 1);
};
const phrasesWithUniqueWords = get(INPUT).filter(onlyUniqueWords);
console.log("solution ", phrasesWithUniqueWords.length);

Is there a better way to write it in FP with pure JavaScript, i.e. no additional FP library? Any other improvement suggestions are welcomed.

\$\endgroup\$
  • \$\begingroup\$ By the description of the problem I would create an isValidPassphrase function. Do you need to count the duplicates? If not, you can probably simplify this. \$\endgroup\$ – elclanrs Jan 11 '18 at 17:44
  • 1
    \$\begingroup\$ you really need to read this.. \$\endgroup\$ – I wrestled a bear once. Jan 11 '18 at 22:16
  • \$\begingroup\$ @Iwrestledabearonce. some of the things he said in his blog isn't true. \$\endgroup\$ – thadeuszlay Jan 12 '18 at 16:25
  • \$\begingroup\$ @thadeuszlay what, specifically? most of it is subjective - it's not really a matter of right vs wrong. \$\endgroup\$ – I wrestled a bear once. Jan 12 '18 at 18:03
1
\$\begingroup\$

I don't remember where I saw it (maybe one of your other posts) but I recently saw a technique for ensuring uniqueness of array elements - iterate over the elements and just return the equality of the current index to the value returned by calling Array.indexOf(). Using that technique here, Array.every() can be used to ensure each word is unique.

With that technique, there is no need to count the number of occurrences of each word and hence the reduction can be removed. Thus countDuplicate can be eliminated and onlyUniqueWords can be simplified like below:

const onlyUniqueWords = phrases => {
    const words = phrases.split(' ');
    return words.every((word, index) => words.indexOf(word) === index);
};

Here is a jsPerf comparing this technique with the original. The original appears to be ~83-86% slower.

In the snippet below (and the jsPerf mentioned above), I replaced the 3rd line (i.e. ...) with two lines similar to those in the problem description. The first inserted line has unique words and the second does not.

const INPUT =
`pphsv ojtou brvhsj cer ntfhlra udeh ccgtyzc zoyzmh jum lugbnk
vxjnf fzqitnj uyfck blnl impo kxoow nngd worcm bdesehw
aa bb cc dd
aa bb cc dd ee cc
caibh nfuk kfnu llfdbz uxjty yxjut jcea`;

const get = input => input.split('\n');
const onlyUniqueWords = phrases => {
  const words = phrases.split(' ');
  return words.every((word, index) => words.indexOf(word) === index);
};

const phrasesWithUniqueWords = get(INPUT).filter(onlyUniqueWords);
console.log("solution ", phrasesWithUniqueWords.length);

P.S. I feel like this technique could very easily apply to your subsequent post for the 2nd part of this..., but perhaps for the sake of varying ideas, I shall refrain from mentioning this in that post...

\$\endgroup\$

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.