Project Euler 8: Largest product in a series in Functional Programming (FP)

Posted on

Problem

I wanted to practice functional programming (fp) without using any library but using vanilla JS only. So I took a problem from Project Euler:

The four adjacent digits in the 1000-digit number that have the
greatest product are 9 × 9 × 8 × 9 = 5832.

73167176531330624919225119674426574742355349194934
96983520312774506326239578318016984801869478851843
85861560789112949495459501737958331952853208805511
12540698747158523863050715693290963295227443043557
66896648950445244523161731856403098711121722383113
62229893423380308135336276614282806444486645238749
30358907296290491560440772390713810515859307960866
70172427121883998797908792274921901699720888093776
65727333001053367881220235421809751254540594752243
52584907711670556013604839586446706324415722155397
53697817977846174064955149290862569321978468622482
83972241375657056057490261407972968652414535100474
82166370484403199890008895243450658541227588666881
16427171479924442928230863465674813919123162824586
17866458359124566529476545682848912883142607690042
24219022671055626321111109370544217506941658960408
07198403850962455444362981230987879927244284909188
84580156166097919133875499200524063689912560717606
05886116467109405077541002256983155200055935729725
71636269561882670428252483600823257530420752963450

Find the thirteen adjacent digits in the 1000-digit number that have
the greatest product. What is the value of this product?

My solution in FP:

(function () {
  'use strict';

  const INPUT =    '7316717653133062491922511967442657474235534919493496983520312774506326239578318016984801869478851843858615607891129494954595017379583319528532088055111254069874715852386305071569329096329522744304355766896648950445244523161731856403098711121722383113622298934233803081353362766142828064444866452387493035890729629049156044077239071381051585930796086670172427121883998797908792274921901699720888093776657273330010533678812202354218097512545405947522435258490771167055601360483958644670632441572215539753697817977846174064955149290862569321978468622482839722413756570560574902614079729686524145351004748216637048440319989000889524345065854122758866688116427171479924442928230863465674813919123162824586178664583591245665294765456828489128831426076900422421902267105562632111110937054421750694165896040807198403850962455444362981230987879927244284909188845801561660979191338754992005240636899125607176060588611646710940507754100225698315520005593572972571636269561882670428252483600823257530420752963450';

  const parser = (maxProduct, number) => {
    const SIZE = 13;
    const multiply = (acc, val) => acc * val;
    const product = number
      .slice(0, SIZE)
      .split('')
      .reduce(multiply);
    const latestMaxProduct = product > maxProduct ? product : maxProduct;

    return number.length < SIZE ?
      latestMaxProduct :
      parser(latestMaxProduct, number.slice(1));
  };
  const solution = parser(0, INPUT);

  console.log("solution ", solution);
})();

Is there a better way to write it in FP (without any libraries and with vanilla JS only)? Also any improvement suggestions are welcomed!

Solution

Some notes about your code:

  • (function () {. Is this old-style wrapping really needed? Isn’t this a node.js script?
  • You parsed INPUT manually from the question. You should probably leave the input as similar as possible to how it’s stated and do the parsing programatically.
  • const multiply = (acc, val) => acc * val;: The variable names reveal how the function is used; instead, keep it generic: const multiply = (x, y) => x * y;. Consider also creating the abstraction product, the product of all numbers in an array.
  • parser(latestMaxProduct, number.slice(1)); You should use recursive calls as a last resort, only when higher-level abstractions (map, filter, reduce, …) are not enough.
  • I’d separate generic functions from the specific code used in the problem. Re-using generic abstractions is one the fundamental principles of FP.

I’d write:

const range = (start, end) => Array.from(new Array(end - start), (x, i) => i + start);
const groupsOf = (xs, n) => range(0, xs.length - n + 1).map(i =>  xs.slice(i, i + n));
const product = xs => xs.reduce((acc, x) => acc * x, 1);
const maximum = xs => Math.max(...xs);

const euler8 = () => {
  const unparsedDigits = `
    73167176531330624919225119674426574742355349194934
    96983520312774506326239578318016984801869478851843
    ...
  `;
  const groupSize = 13;

  const digits = unparsedDigits.replace(/[^d]/g, "").split("").map(c => parseInt(c));
  return maximum(groupsOf(digits, groupSize).map(product));
}

console.log(euler8());

Leave a Reply

Your email address will not be published. Required fields are marked *