From 8a38f2f9e8cbde0c0a10be9397720703f82e8829 Mon Sep 17 00:00:00 2001 From: Eric Ti Yu Chiang Date: Tue, 13 Nov 2018 12:02:35 -0500 Subject: [PATCH 1/5] Use named export for largest series product Per #436, convert default export to named export for largest series product exercise. Change from class style `new Series(x).largestProduct(y)` to `largestSeriesProduct(x, y)` since there is no need to keep state. --- exercises/largest-series-product/example.js | 68 ++++++++----------- .../largest-series-product.spec.js | 26 +++---- 2 files changed, 42 insertions(+), 52 deletions(-) diff --git a/exercises/largest-series-product/example.js b/exercises/largest-series-product/example.js index 1c3e75a4c8..0bff2839c1 100644 --- a/exercises/largest-series-product/example.js +++ b/exercises/largest-series-product/example.js @@ -1,49 +1,39 @@ -export default class Series { - constructor(numberString) { - if (numberString.match('[^0-9]')) { - throw new Error('Invalid input.'); - } +const getDigits = numberString => [...numberString].map(digit => parseInt(digit, 10)); - this.numberString = numberString; - this.digits = this.getDigits(); - } +const slices = (digits, sliceSize) => { + const result = []; + let slice = []; - getDigits() { - return [...this.numberString].map(digit => parseInt(digit, 10)); + if (sliceSize > digits.length) { + throw new Error('Slice size is too big.'); } - largestProduct(size) { - if (size < 0) { - throw new Error('Invalid input.'); + for (let i = 0; i < digits.length - sliceSize + 1; i++) { + for (let j = 0; j < sliceSize; j++) { + slice.push(digits[i + j]); } - - let product, - max = 0; - this.slices(size).forEach((slice) => { - product = slice.reduce((a, b) => a * b, 1); - if (product > max) { - max = product; - } - }); - return max; + result.push(slice); + slice = []; } - slices(sliceSize) { - const result = []; - let slice = []; + return result; +}; - if (sliceSize > this.digits.length) { - throw new Error('Slice size is too big.'); - } +export const largestSeriesProduct = (numberString, size) => { + if (numberString.match('[^0-9]')) { + throw new Error('Invalid input.'); + } + if (size < 0) { + throw new Error('Invalid input.'); + } - for (let i = 0; i < this.digits.length - sliceSize + 1; i++) { - for (let j = 0; j < sliceSize; j++) { - slice.push(this.digits[i + j]); - } - result.push(slice); - slice = []; + let product, + max = 0; + slices(getDigits(numberString), size).forEach((slice) => { + let product = slice.reduce((a, b) => a * b, 1); + if (product > max) { + max = product; } - - return result; - } -} + }); + return max; +}; diff --git a/exercises/largest-series-product/largest-series-product.spec.js b/exercises/largest-series-product/largest-series-product.spec.js index f94d51624c..f541bafc94 100644 --- a/exercises/largest-series-product/largest-series-product.spec.js +++ b/exercises/largest-series-product/largest-series-product.spec.js @@ -1,16 +1,16 @@ -import Series from './largest-series-product'; +import { largestSeriesProduct } from './largest-series-product'; describe('Series', () => { test('can get the largest product of 2', () => { - expect(new Series('0123456789').largestProduct(2)).toBe(72); + expect(largestSeriesProduct('0123456789', 2)).toBe(72); }); xtest('works for a tiny number', () => { - expect(new Series('19').largestProduct(2)).toBe(9); + expect(largestSeriesProduct('19', 2)).toBe(9); }); xtest('can get the largest product of 3', () => { - expect(new Series('1027839564').largestProduct(3)).toBe(270); + expect(largestSeriesProduct('1027839564', 3)).toBe(270); }); xtest('can get the largest product of a big number', () => { @@ -23,46 +23,46 @@ describe('Series', () => { '99244429282308634656748139191231628245861786645835912456652947654568284891288314260769004224219022671055626321111' + '10937054421750694165896040807198403850962455444362981230987879927244284909188845801561660979191338754992005240636' + '899125607176060588611646710940507754100225698315520005593572972571636269561882670428252483600823257530420752963450'; - expect(new Series(largeNumber).largestProduct(13)).toBe(23514624000); + expect(largestSeriesProduct(largeNumber, 13)).toBe(23514624000); }); xtest('returns 0 if all digits are zero', () => { - expect(new Series('0000').largestProduct(2)).toBe(0); + expect(largestSeriesProduct('0000', 2)).toBe(0); }); xtest('returns 0 if all spans contain zero', () => { - expect(new Series('99099').largestProduct(3)).toBe(0); + expect(largestSeriesProduct('99099', 3)).toBe(0); }); xtest('rejects invalid character in input', () => { expect(() => { - new Series('1234a5').largestProduct('2'); + largestSeriesProduct('1234a5', '2'); }).toThrow(new Error('Invalid input.')); }); xtest('rejects negative span', () => { expect(() => { - new Series('12345').largestProduct(-1); + largestSeriesProduct('12345', -1); }).toThrow(new Error('Invalid input.')); }); xtest('returns 1 for empty string and zero slice length', () => { - expect(new Series('').largestProduct(0)).toBe(1); + expect(largestSeriesProduct('', 0)).toBe(1); }); xtest('returns 1 for non-empty string and zero slice length', () => { - expect(new Series('123').largestProduct(0)).toBe(1); + expect(largestSeriesProduct('123', 0)).toBe(1); }); xtest('throws an error for slices bigger than the number', () => { expect(() => { - new Series('123').largestProduct(4); + largestSeriesProduct('123', 4); }).toThrow(new Error('Slice size is too big.')); }); xtest('throws an error for empty string and non-zero slice length', () => { expect(() => { - new Series('').largestProduct(1); + largestSeriesProduct('', 1); }).toThrow(new Error('Slice size is too big.')); }); }); From c2d080c51591b9d9e24915d773b8ce9ca8d99140 Mon Sep 17 00:00:00 2001 From: Eric Ti Yu Chiang Date: Tue, 13 Nov 2018 12:09:24 -0500 Subject: [PATCH 2/5] Move guard clause from `slices` to `largestSeriesProduct` This refactor is to validate input as early as possible. --- exercises/largest-series-product/example.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/exercises/largest-series-product/example.js b/exercises/largest-series-product/example.js index 0bff2839c1..8bae3501e7 100644 --- a/exercises/largest-series-product/example.js +++ b/exercises/largest-series-product/example.js @@ -4,10 +4,6 @@ const slices = (digits, sliceSize) => { const result = []; let slice = []; - if (sliceSize > digits.length) { - throw new Error('Slice size is too big.'); - } - for (let i = 0; i < digits.length - sliceSize + 1; i++) { for (let j = 0; j < sliceSize; j++) { slice.push(digits[i + j]); @@ -26,6 +22,9 @@ export const largestSeriesProduct = (numberString, size) => { if (size < 0) { throw new Error('Invalid input.'); } + if (size > numberString.length) { + throw new Error('Slice size is too big.'); + } let product, max = 0; From e9e737b7813d74b9adb5bcf5546c4fc493f771e8 Mon Sep 17 00:00:00 2001 From: Eric Ti Yu Chiang Date: Tue, 13 Nov 2018 12:20:06 -0500 Subject: [PATCH 3/5] Simplify `slices` logic using `Array.slice` --- exercises/largest-series-product/example.js | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/exercises/largest-series-product/example.js b/exercises/largest-series-product/example.js index 8bae3501e7..7d848343ab 100644 --- a/exercises/largest-series-product/example.js +++ b/exercises/largest-series-product/example.js @@ -2,16 +2,9 @@ const getDigits = numberString => [...numberString].map(digit => parseInt(digit, const slices = (digits, sliceSize) => { const result = []; - let slice = []; - - for (let i = 0; i < digits.length - sliceSize + 1; i++) { - for (let j = 0; j < sliceSize; j++) { - slice.push(digits[i + j]); - } - result.push(slice); - slice = []; + for (let i = 0; i < digits.length - sliceSize + 1; i += 1) { + result.push(digits.slice(i, i + sliceSize)); } - return result; }; From c450f53bd3c7b138f27569d60a553d75636e3aa8 Mon Sep 17 00:00:00 2001 From: Eric Ti Yu Chiang Date: Tue, 13 Nov 2018 12:29:00 -0500 Subject: [PATCH 4/5] Simplify search for largest product using `reduce` Instead of `forEach`, use `reduce` to convey clearly `max` as an accumulator. Also, `product` only need to be within the reducing function. --- exercises/largest-series-product/example.js | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/exercises/largest-series-product/example.js b/exercises/largest-series-product/example.js index 7d848343ab..a60440ac36 100644 --- a/exercises/largest-series-product/example.js +++ b/exercises/largest-series-product/example.js @@ -19,13 +19,8 @@ export const largestSeriesProduct = (numberString, size) => { throw new Error('Slice size is too big.'); } - let product, - max = 0; - slices(getDigits(numberString), size).forEach((slice) => { - let product = slice.reduce((a, b) => a * b, 1); - if (product > max) { - max = product; - } - }); - return max; + return slices(getDigits(numberString), size).reduce((max, slice) => { + const product = slice.reduce((a, b) => a * b, 1); + return product > max ? product : max; + }, 0); }; From 40504cf7821d0c26b3af56c8816356bd652ea593 Mon Sep 17 00:00:00 2001 From: Eric Ti Yu Chiang Date: Tue, 13 Nov 2018 12:37:20 -0500 Subject: [PATCH 5/5] lint largest series product exercise --- .eslintignore | 1 - .../largest-series-product.spec.js | 18 +++++++++--------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/.eslintignore b/.eslintignore index 43d2f5e9b9..f97a5b45c3 100644 --- a/.eslintignore +++ b/.eslintignore @@ -9,7 +9,6 @@ food-chain forth grade-school grains -largest-series-product linked-list list-ops meetup diff --git a/exercises/largest-series-product/largest-series-product.spec.js b/exercises/largest-series-product/largest-series-product.spec.js index f541bafc94..06875a80fc 100644 --- a/exercises/largest-series-product/largest-series-product.spec.js +++ b/exercises/largest-series-product/largest-series-product.spec.js @@ -14,15 +14,15 @@ describe('Series', () => { }); xtest('can get the largest product of a big number', () => { - const largeNumber = '73167176531330624919225119674426574742355349194934969835203127745063262395783180169848018694788' + - '51843858615607891129494954595017379583319528532088055111254069874715852386305071569329096329522744304355766896648' + - '95044524452316173185640309871112172238311362229893423380308135336276614282806444486645238749303589072962904915604' + - '40772390713810515859307960866701724271218839987979087922749219016997208880937766572733300105336788122023542180975' + - '12545405947522435258490771167055601360483958644670632441572215539753697817977846174064955149290862569321978468622' + - '48283972241375657056057490261407972968652414535100474821663704844031998900088952434506585412275886668811642717147' + - '99244429282308634656748139191231628245861786645835912456652947654568284891288314260769004224219022671055626321111' + - '10937054421750694165896040807198403850962455444362981230987879927244284909188845801561660979191338754992005240636' + - '899125607176060588611646710940507754100225698315520005593572972571636269561882670428252483600823257530420752963450'; + const largeNumber = '73167176531330624919225119674426574742355349194934969835203127745063262395783180169848018694788' + + '51843858615607891129494954595017379583319528532088055111254069874715852386305071569329096329522744304355766896648' + + '95044524452316173185640309871112172238311362229893423380308135336276614282806444486645238749303589072962904915604' + + '40772390713810515859307960866701724271218839987979087922749219016997208880937766572733300105336788122023542180975' + + '12545405947522435258490771167055601360483958644670632441572215539753697817977846174064955149290862569321978468622' + + '48283972241375657056057490261407972968652414535100474821663704844031998900088952434506585412275886668811642717147' + + '99244429282308634656748139191231628245861786645835912456652947654568284891288314260769004224219022671055626321111' + + '10937054421750694165896040807198403850962455444362981230987879927244284909188845801561660979191338754992005240636' + + '899125607176060588611646710940507754100225698315520005593572972571636269561882670428252483600823257530420752963450'; expect(largestSeriesProduct(largeNumber, 13)).toBe(23514624000); });