Advent of code 2017 Day 2 (2) in Functional Programming (FP)

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP





.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;







up vote
1
down vote

favorite












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 2nd part of Day 2):



https://adventofcode.com/2017/day/2



I'm doing the 2nd part of Day 2. You can only access the 2nd part once you solved the 1st part.



To access the 2nd part type in this number 50376 or check out the solution here: Advent of Code Day 2 (1) in Functional programming (FP)




It sounds like the goal is to find the only two numbers in each row
where one evenly divides the other - that is, where the result of the
division operation is a whole number. They would like you to find
those numbers on each line, divide them, and add up each line's
result.



For example, given the following spreadsheet:



  • 5 9 2 8

  • 9 4 7 3

  • 3 8 6 5

In the first row, the only two numbers that evenly divide are 8 and 2;
the result of this division is 4. In the second row, the two numbers
are 9 and 3; the result is 3. In the third row, the result is 2. In
this example, the sum of the results would be 4 + 3 + 2 = 9.




My solution in FP:



/*jshint esversion: 6*/

'use strict';

const INPUT =
`6046 6349 208 276 4643 1085 1539 4986 7006 5374 252 4751 226 6757 7495 2923
1432 1538 1761 1658 104 826 806 109 939 886 1497 280 1412 127 1651 156
244 1048 133 232 226 1072 883 1045 1130 252 1038 1022 471 70 1222 957
87 172 93 73 67 192 249 239 155 23 189 106 55 174 181 116
5871 204 6466 6437 5716 232 1513 7079 6140 268 350 6264 6420 3904 272 5565
1093 838 90 1447 1224 744 1551 59 328 1575 1544 1360 71 1583 75 370
213 166 7601 6261 247 210 4809 6201 6690 6816 7776 2522 5618 580 2236 3598
92 168 96 132 196 157 116 94 253 128 60 167 192 156 76 148
187 111 141 143 45 132 140 402 134 227 342 276 449 148 170 348
1894 1298 1531 1354 1801 974 85 93 1712 130 1705 110 314 107 449 350
1662 1529 784 1704 1187 83 422 146 147 1869 1941 110 525 1293 158 1752
162 1135 3278 1149 3546 3686 182 149 119 1755 3656 2126 244 3347 157 865
2049 6396 4111 6702 251 669 1491 245 210 4314 6265 694 5131 228 6195 6090
458 448 324 235 69 79 94 78 515 68 380 64 440 508 503 452
198 216 5700 4212 2370 143 5140 190 4934 539 5054 3707 6121 5211 549 2790
3021 3407 218 1043 449 214 1594 3244 3097 286 114 223 1214 3102 257 3345`;

const sum = (a, b) => a + b;
const evenlyDiv = (diff, val) =>
const row = val.split(/t/);
return diff.concat(row
.reduce((d, v, i, line) =>
return d + line.reduce((reduceRes, runningVar) =>
return (runningVar % v === 0 && runningVar !== v) ?
reduceRes + (runningVar / v) :
reduceRes;
, 0);
, 0));
;
const solution = INPUT.split(/n/)
.reduce(evenlyDiv, )
.reduce(sum);

console.log("solution ", solution);



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







share|improve this question





















  • @JerryCoffin: That's because I'm doing the 2nd part (as I clearly stated in the headline as well as in the description) of Day 2. You can only access the 2nd part once you solved the 1st part. To access the 2nd part type in this number 50376 or check out the solution here: codereview.stackexchange.com/questions/184477/…
    – thadeuszlay
    Jan 6 at 19:38










  • @JerryCoffin done. Thanks for the suggestion.
    – thadeuszlay
    Jan 6 at 19:41

















up vote
1
down vote

favorite












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 2nd part of Day 2):



https://adventofcode.com/2017/day/2



I'm doing the 2nd part of Day 2. You can only access the 2nd part once you solved the 1st part.



To access the 2nd part type in this number 50376 or check out the solution here: Advent of Code Day 2 (1) in Functional programming (FP)




It sounds like the goal is to find the only two numbers in each row
where one evenly divides the other - that is, where the result of the
division operation is a whole number. They would like you to find
those numbers on each line, divide them, and add up each line's
result.



For example, given the following spreadsheet:



  • 5 9 2 8

  • 9 4 7 3

  • 3 8 6 5

In the first row, the only two numbers that evenly divide are 8 and 2;
the result of this division is 4. In the second row, the two numbers
are 9 and 3; the result is 3. In the third row, the result is 2. In
this example, the sum of the results would be 4 + 3 + 2 = 9.




My solution in FP:



/*jshint esversion: 6*/

'use strict';

const INPUT =
`6046 6349 208 276 4643 1085 1539 4986 7006 5374 252 4751 226 6757 7495 2923
1432 1538 1761 1658 104 826 806 109 939 886 1497 280 1412 127 1651 156
244 1048 133 232 226 1072 883 1045 1130 252 1038 1022 471 70 1222 957
87 172 93 73 67 192 249 239 155 23 189 106 55 174 181 116
5871 204 6466 6437 5716 232 1513 7079 6140 268 350 6264 6420 3904 272 5565
1093 838 90 1447 1224 744 1551 59 328 1575 1544 1360 71 1583 75 370
213 166 7601 6261 247 210 4809 6201 6690 6816 7776 2522 5618 580 2236 3598
92 168 96 132 196 157 116 94 253 128 60 167 192 156 76 148
187 111 141 143 45 132 140 402 134 227 342 276 449 148 170 348
1894 1298 1531 1354 1801 974 85 93 1712 130 1705 110 314 107 449 350
1662 1529 784 1704 1187 83 422 146 147 1869 1941 110 525 1293 158 1752
162 1135 3278 1149 3546 3686 182 149 119 1755 3656 2126 244 3347 157 865
2049 6396 4111 6702 251 669 1491 245 210 4314 6265 694 5131 228 6195 6090
458 448 324 235 69 79 94 78 515 68 380 64 440 508 503 452
198 216 5700 4212 2370 143 5140 190 4934 539 5054 3707 6121 5211 549 2790
3021 3407 218 1043 449 214 1594 3244 3097 286 114 223 1214 3102 257 3345`;

const sum = (a, b) => a + b;
const evenlyDiv = (diff, val) =>
const row = val.split(/t/);
return diff.concat(row
.reduce((d, v, i, line) =>
return d + line.reduce((reduceRes, runningVar) =>
return (runningVar % v === 0 && runningVar !== v) ?
reduceRes + (runningVar / v) :
reduceRes;
, 0);
, 0));
;
const solution = INPUT.split(/n/)
.reduce(evenlyDiv, )
.reduce(sum);

console.log("solution ", solution);



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







share|improve this question





















  • @JerryCoffin: That's because I'm doing the 2nd part (as I clearly stated in the headline as well as in the description) of Day 2. You can only access the 2nd part once you solved the 1st part. To access the 2nd part type in this number 50376 or check out the solution here: codereview.stackexchange.com/questions/184477/…
    – thadeuszlay
    Jan 6 at 19:38










  • @JerryCoffin done. Thanks for the suggestion.
    – thadeuszlay
    Jan 6 at 19:41













up vote
1
down vote

favorite









up vote
1
down vote

favorite











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 2nd part of Day 2):



https://adventofcode.com/2017/day/2



I'm doing the 2nd part of Day 2. You can only access the 2nd part once you solved the 1st part.



To access the 2nd part type in this number 50376 or check out the solution here: Advent of Code Day 2 (1) in Functional programming (FP)




It sounds like the goal is to find the only two numbers in each row
where one evenly divides the other - that is, where the result of the
division operation is a whole number. They would like you to find
those numbers on each line, divide them, and add up each line's
result.



For example, given the following spreadsheet:



  • 5 9 2 8

  • 9 4 7 3

  • 3 8 6 5

In the first row, the only two numbers that evenly divide are 8 and 2;
the result of this division is 4. In the second row, the two numbers
are 9 and 3; the result is 3. In the third row, the result is 2. In
this example, the sum of the results would be 4 + 3 + 2 = 9.




My solution in FP:



/*jshint esversion: 6*/

'use strict';

const INPUT =
`6046 6349 208 276 4643 1085 1539 4986 7006 5374 252 4751 226 6757 7495 2923
1432 1538 1761 1658 104 826 806 109 939 886 1497 280 1412 127 1651 156
244 1048 133 232 226 1072 883 1045 1130 252 1038 1022 471 70 1222 957
87 172 93 73 67 192 249 239 155 23 189 106 55 174 181 116
5871 204 6466 6437 5716 232 1513 7079 6140 268 350 6264 6420 3904 272 5565
1093 838 90 1447 1224 744 1551 59 328 1575 1544 1360 71 1583 75 370
213 166 7601 6261 247 210 4809 6201 6690 6816 7776 2522 5618 580 2236 3598
92 168 96 132 196 157 116 94 253 128 60 167 192 156 76 148
187 111 141 143 45 132 140 402 134 227 342 276 449 148 170 348
1894 1298 1531 1354 1801 974 85 93 1712 130 1705 110 314 107 449 350
1662 1529 784 1704 1187 83 422 146 147 1869 1941 110 525 1293 158 1752
162 1135 3278 1149 3546 3686 182 149 119 1755 3656 2126 244 3347 157 865
2049 6396 4111 6702 251 669 1491 245 210 4314 6265 694 5131 228 6195 6090
458 448 324 235 69 79 94 78 515 68 380 64 440 508 503 452
198 216 5700 4212 2370 143 5140 190 4934 539 5054 3707 6121 5211 549 2790
3021 3407 218 1043 449 214 1594 3244 3097 286 114 223 1214 3102 257 3345`;

const sum = (a, b) => a + b;
const evenlyDiv = (diff, val) =>
const row = val.split(/t/);
return diff.concat(row
.reduce((d, v, i, line) =>
return d + line.reduce((reduceRes, runningVar) =>
return (runningVar % v === 0 && runningVar !== v) ?
reduceRes + (runningVar / v) :
reduceRes;
, 0);
, 0));
;
const solution = INPUT.split(/n/)
.reduce(evenlyDiv, )
.reduce(sum);

console.log("solution ", solution);



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







share|improve this question













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 2nd part of Day 2):



https://adventofcode.com/2017/day/2



I'm doing the 2nd part of Day 2. You can only access the 2nd part once you solved the 1st part.



To access the 2nd part type in this number 50376 or check out the solution here: Advent of Code Day 2 (1) in Functional programming (FP)




It sounds like the goal is to find the only two numbers in each row
where one evenly divides the other - that is, where the result of the
division operation is a whole number. They would like you to find
those numbers on each line, divide them, and add up each line's
result.



For example, given the following spreadsheet:



  • 5 9 2 8

  • 9 4 7 3

  • 3 8 6 5

In the first row, the only two numbers that evenly divide are 8 and 2;
the result of this division is 4. In the second row, the two numbers
are 9 and 3; the result is 3. In the third row, the result is 2. In
this example, the sum of the results would be 4 + 3 + 2 = 9.




My solution in FP:



/*jshint esversion: 6*/

'use strict';

const INPUT =
`6046 6349 208 276 4643 1085 1539 4986 7006 5374 252 4751 226 6757 7495 2923
1432 1538 1761 1658 104 826 806 109 939 886 1497 280 1412 127 1651 156
244 1048 133 232 226 1072 883 1045 1130 252 1038 1022 471 70 1222 957
87 172 93 73 67 192 249 239 155 23 189 106 55 174 181 116
5871 204 6466 6437 5716 232 1513 7079 6140 268 350 6264 6420 3904 272 5565
1093 838 90 1447 1224 744 1551 59 328 1575 1544 1360 71 1583 75 370
213 166 7601 6261 247 210 4809 6201 6690 6816 7776 2522 5618 580 2236 3598
92 168 96 132 196 157 116 94 253 128 60 167 192 156 76 148
187 111 141 143 45 132 140 402 134 227 342 276 449 148 170 348
1894 1298 1531 1354 1801 974 85 93 1712 130 1705 110 314 107 449 350
1662 1529 784 1704 1187 83 422 146 147 1869 1941 110 525 1293 158 1752
162 1135 3278 1149 3546 3686 182 149 119 1755 3656 2126 244 3347 157 865
2049 6396 4111 6702 251 669 1491 245 210 4314 6265 694 5131 228 6195 6090
458 448 324 235 69 79 94 78 515 68 380 64 440 508 503 452
198 216 5700 4212 2370 143 5140 190 4934 539 5054 3707 6121 5211 549 2790
3021 3407 218 1043 449 214 1594 3244 3097 286 114 223 1214 3102 257 3345`;

const sum = (a, b) => a + b;
const evenlyDiv = (diff, val) =>
const row = val.split(/t/);
return diff.concat(row
.reduce((d, v, i, line) =>
return d + line.reduce((reduceRes, runningVar) =>
return (runningVar % v === 0 && runningVar !== v) ?
reduceRes + (runningVar / v) :
reduceRes;
, 0);
, 0));
;
const solution = INPUT.split(/n/)
.reduce(evenlyDiv, )
.reduce(sum);

console.log("solution ", solution);



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









share|improve this question












share|improve this question




share|improve this question








edited Jan 7 at 13:40
























asked Jan 6 at 19:22









thadeuszlay

435212




435212











  • @JerryCoffin: That's because I'm doing the 2nd part (as I clearly stated in the headline as well as in the description) of Day 2. You can only access the 2nd part once you solved the 1st part. To access the 2nd part type in this number 50376 or check out the solution here: codereview.stackexchange.com/questions/184477/…
    – thadeuszlay
    Jan 6 at 19:38










  • @JerryCoffin done. Thanks for the suggestion.
    – thadeuszlay
    Jan 6 at 19:41

















  • @JerryCoffin: That's because I'm doing the 2nd part (as I clearly stated in the headline as well as in the description) of Day 2. You can only access the 2nd part once you solved the 1st part. To access the 2nd part type in this number 50376 or check out the solution here: codereview.stackexchange.com/questions/184477/…
    – thadeuszlay
    Jan 6 at 19:38










  • @JerryCoffin done. Thanks for the suggestion.
    – thadeuszlay
    Jan 6 at 19:41
















@JerryCoffin: That's because I'm doing the 2nd part (as I clearly stated in the headline as well as in the description) of Day 2. You can only access the 2nd part once you solved the 1st part. To access the 2nd part type in this number 50376 or check out the solution here: codereview.stackexchange.com/questions/184477/…
– thadeuszlay
Jan 6 at 19:38




@JerryCoffin: That's because I'm doing the 2nd part (as I clearly stated in the headline as well as in the description) of Day 2. You can only access the 2nd part once you solved the 1st part. To access the 2nd part type in this number 50376 or check out the solution here: codereview.stackexchange.com/questions/184477/…
– thadeuszlay
Jan 6 at 19:38












@JerryCoffin done. Thanks for the suggestion.
– thadeuszlay
Jan 6 at 19:41





@JerryCoffin done. Thanks for the suggestion.
– thadeuszlay
Jan 6 at 19:41











1 Answer
1






active

oldest

votes

















up vote
1
down vote



accepted










While your code works, it took me a few tries to really understand how it works. I believe this is primarily caused by the deep nesting of evenlyDiv. FP is great for reusable code, which makes helper functions a really good idea. In this case, by using a few helpers you can make the code more readable.



A few pointers on your current solution:



  1. Don't use strings as numbers. Sure, it might work right now because division can't concatenate strings like addition can, but it is a dangerous habit to get into.

  2. There is no need to use a regular expression in this case to split the input into rows and columns. .split(/n/) is the same as .split('n').


  3. (d, v, i, line) is a lot of parameters, in this case you don't need two of them. Instead of line, you can just use row, and you never used i anyways.

  4. Don't default to reduce, the original function can be easily simplified by using map instead and just dropping the diff parameter.

  5. Try to avoid meaningless variable names. For very simple functions, it is fine to just use a, and b, but for anything longer than a line (and even some functions of only one line) it makes the code much more difficult to scan when another programmer in 6 months (you) looks at it.


Here is how I would implement the solution (assuming a relatively small table, if the table is very large, some optimization would be a good idea).






const INPUT = `5t9t2t8
9t4t7t3
3t8t6t5`;

// Contained in most FP libraries, but simple to write
const unary = fn => arg => fn(arg)

const sum = (a, b) => a + b
const isNot = a => b => a !== b
const isDivisible = dividend => divisor => dividend % divisor === 0;

/**
* Takes an array of numbers, returns the result of the division
* of the first two numbers which divide evenly or 0 if no two
* numbers are divisible.
*/
const divideEvenly = numbers =>
return numbers.reduce((carry, n) =>
if (carry) return carry;

const divisor = numbers
.filter(isNot(n))
.find(isDivisible(n));
return divisor == null ? carry : n / divisor;
, 0);


// Without unary, parseInt would fail due to trying to parse with different bases
const solution = INPUT.split('n')
.map(line => line.split('t').map(unary(parseInt)))
.map(divideEvenly)
.reduce(sum, 0);

console.log("solution ", solution);








share|improve this answer





















  • "There is no need to use a regular expression" - why would you discourage from using regex? Are they slower or less declarative?
    – thadeuszlay
    Jan 7 at 13:57










  • @thadeuszlay Regex is generally slower, yes, but I wouldn't worry about that here. The reason I recommend just using a string is that regex is such a powerful tool that really isn't necessary here. If you needed to match multiple combinations, using regex is absolutely the way to go, but for just a single character, or a simple sequence of characters, it is easier to just use a string. It is kind of like importing jQuery just to use $('p').remove() once in your code.
    – Gerrit0
    Jan 7 at 19:17










  • I don't get why the unary function is needed. I know that without it wouldn't work properly. But this works without the unary function const parse = line => line.split('t') .map(toInt);
    – thadeuszlay
    Jan 13 at 10:22










  • You can write everything without the unary function, true but it often results in cleaner code as you can avoid functions whose sole purpose is to call another function with one argument.
    – Gerrit0
    Jan 13 at 17:05










Your Answer




StackExchange.ifUsing("editor", function ()
return StackExchange.using("mathjaxEditing", function ()
StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix)
StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
);
);
, "mathjax-editing");

StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");

StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "196"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);

else
createEditor();

);

function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
convertImagesToLinks: false,
noModals: false,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);



);








 

draft saved


draft discarded


















StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f184476%2fadvent-of-code-2017-day-2-2-in-functional-programming-fp%23new-answer', 'question_page');

);

Post as a guest






























1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes








up vote
1
down vote



accepted










While your code works, it took me a few tries to really understand how it works. I believe this is primarily caused by the deep nesting of evenlyDiv. FP is great for reusable code, which makes helper functions a really good idea. In this case, by using a few helpers you can make the code more readable.



A few pointers on your current solution:



  1. Don't use strings as numbers. Sure, it might work right now because division can't concatenate strings like addition can, but it is a dangerous habit to get into.

  2. There is no need to use a regular expression in this case to split the input into rows and columns. .split(/n/) is the same as .split('n').


  3. (d, v, i, line) is a lot of parameters, in this case you don't need two of them. Instead of line, you can just use row, and you never used i anyways.

  4. Don't default to reduce, the original function can be easily simplified by using map instead and just dropping the diff parameter.

  5. Try to avoid meaningless variable names. For very simple functions, it is fine to just use a, and b, but for anything longer than a line (and even some functions of only one line) it makes the code much more difficult to scan when another programmer in 6 months (you) looks at it.


Here is how I would implement the solution (assuming a relatively small table, if the table is very large, some optimization would be a good idea).






const INPUT = `5t9t2t8
9t4t7t3
3t8t6t5`;

// Contained in most FP libraries, but simple to write
const unary = fn => arg => fn(arg)

const sum = (a, b) => a + b
const isNot = a => b => a !== b
const isDivisible = dividend => divisor => dividend % divisor === 0;

/**
* Takes an array of numbers, returns the result of the division
* of the first two numbers which divide evenly or 0 if no two
* numbers are divisible.
*/
const divideEvenly = numbers =>
return numbers.reduce((carry, n) =>
if (carry) return carry;

const divisor = numbers
.filter(isNot(n))
.find(isDivisible(n));
return divisor == null ? carry : n / divisor;
, 0);


// Without unary, parseInt would fail due to trying to parse with different bases
const solution = INPUT.split('n')
.map(line => line.split('t').map(unary(parseInt)))
.map(divideEvenly)
.reduce(sum, 0);

console.log("solution ", solution);








share|improve this answer





















  • "There is no need to use a regular expression" - why would you discourage from using regex? Are they slower or less declarative?
    – thadeuszlay
    Jan 7 at 13:57










  • @thadeuszlay Regex is generally slower, yes, but I wouldn't worry about that here. The reason I recommend just using a string is that regex is such a powerful tool that really isn't necessary here. If you needed to match multiple combinations, using regex is absolutely the way to go, but for just a single character, or a simple sequence of characters, it is easier to just use a string. It is kind of like importing jQuery just to use $('p').remove() once in your code.
    – Gerrit0
    Jan 7 at 19:17










  • I don't get why the unary function is needed. I know that without it wouldn't work properly. But this works without the unary function const parse = line => line.split('t') .map(toInt);
    – thadeuszlay
    Jan 13 at 10:22










  • You can write everything without the unary function, true but it often results in cleaner code as you can avoid functions whose sole purpose is to call another function with one argument.
    – Gerrit0
    Jan 13 at 17:05














up vote
1
down vote



accepted










While your code works, it took me a few tries to really understand how it works. I believe this is primarily caused by the deep nesting of evenlyDiv. FP is great for reusable code, which makes helper functions a really good idea. In this case, by using a few helpers you can make the code more readable.



A few pointers on your current solution:



  1. Don't use strings as numbers. Sure, it might work right now because division can't concatenate strings like addition can, but it is a dangerous habit to get into.

  2. There is no need to use a regular expression in this case to split the input into rows and columns. .split(/n/) is the same as .split('n').


  3. (d, v, i, line) is a lot of parameters, in this case you don't need two of them. Instead of line, you can just use row, and you never used i anyways.

  4. Don't default to reduce, the original function can be easily simplified by using map instead and just dropping the diff parameter.

  5. Try to avoid meaningless variable names. For very simple functions, it is fine to just use a, and b, but for anything longer than a line (and even some functions of only one line) it makes the code much more difficult to scan when another programmer in 6 months (you) looks at it.


Here is how I would implement the solution (assuming a relatively small table, if the table is very large, some optimization would be a good idea).






const INPUT = `5t9t2t8
9t4t7t3
3t8t6t5`;

// Contained in most FP libraries, but simple to write
const unary = fn => arg => fn(arg)

const sum = (a, b) => a + b
const isNot = a => b => a !== b
const isDivisible = dividend => divisor => dividend % divisor === 0;

/**
* Takes an array of numbers, returns the result of the division
* of the first two numbers which divide evenly or 0 if no two
* numbers are divisible.
*/
const divideEvenly = numbers =>
return numbers.reduce((carry, n) =>
if (carry) return carry;

const divisor = numbers
.filter(isNot(n))
.find(isDivisible(n));
return divisor == null ? carry : n / divisor;
, 0);


// Without unary, parseInt would fail due to trying to parse with different bases
const solution = INPUT.split('n')
.map(line => line.split('t').map(unary(parseInt)))
.map(divideEvenly)
.reduce(sum, 0);

console.log("solution ", solution);








share|improve this answer





















  • "There is no need to use a regular expression" - why would you discourage from using regex? Are they slower or less declarative?
    – thadeuszlay
    Jan 7 at 13:57










  • @thadeuszlay Regex is generally slower, yes, but I wouldn't worry about that here. The reason I recommend just using a string is that regex is such a powerful tool that really isn't necessary here. If you needed to match multiple combinations, using regex is absolutely the way to go, but for just a single character, or a simple sequence of characters, it is easier to just use a string. It is kind of like importing jQuery just to use $('p').remove() once in your code.
    – Gerrit0
    Jan 7 at 19:17










  • I don't get why the unary function is needed. I know that without it wouldn't work properly. But this works without the unary function const parse = line => line.split('t') .map(toInt);
    – thadeuszlay
    Jan 13 at 10:22










  • You can write everything without the unary function, true but it often results in cleaner code as you can avoid functions whose sole purpose is to call another function with one argument.
    – Gerrit0
    Jan 13 at 17:05












up vote
1
down vote



accepted







up vote
1
down vote



accepted






While your code works, it took me a few tries to really understand how it works. I believe this is primarily caused by the deep nesting of evenlyDiv. FP is great for reusable code, which makes helper functions a really good idea. In this case, by using a few helpers you can make the code more readable.



A few pointers on your current solution:



  1. Don't use strings as numbers. Sure, it might work right now because division can't concatenate strings like addition can, but it is a dangerous habit to get into.

  2. There is no need to use a regular expression in this case to split the input into rows and columns. .split(/n/) is the same as .split('n').


  3. (d, v, i, line) is a lot of parameters, in this case you don't need two of them. Instead of line, you can just use row, and you never used i anyways.

  4. Don't default to reduce, the original function can be easily simplified by using map instead and just dropping the diff parameter.

  5. Try to avoid meaningless variable names. For very simple functions, it is fine to just use a, and b, but for anything longer than a line (and even some functions of only one line) it makes the code much more difficult to scan when another programmer in 6 months (you) looks at it.


Here is how I would implement the solution (assuming a relatively small table, if the table is very large, some optimization would be a good idea).






const INPUT = `5t9t2t8
9t4t7t3
3t8t6t5`;

// Contained in most FP libraries, but simple to write
const unary = fn => arg => fn(arg)

const sum = (a, b) => a + b
const isNot = a => b => a !== b
const isDivisible = dividend => divisor => dividend % divisor === 0;

/**
* Takes an array of numbers, returns the result of the division
* of the first two numbers which divide evenly or 0 if no two
* numbers are divisible.
*/
const divideEvenly = numbers =>
return numbers.reduce((carry, n) =>
if (carry) return carry;

const divisor = numbers
.filter(isNot(n))
.find(isDivisible(n));
return divisor == null ? carry : n / divisor;
, 0);


// Without unary, parseInt would fail due to trying to parse with different bases
const solution = INPUT.split('n')
.map(line => line.split('t').map(unary(parseInt)))
.map(divideEvenly)
.reduce(sum, 0);

console.log("solution ", solution);








share|improve this answer













While your code works, it took me a few tries to really understand how it works. I believe this is primarily caused by the deep nesting of evenlyDiv. FP is great for reusable code, which makes helper functions a really good idea. In this case, by using a few helpers you can make the code more readable.



A few pointers on your current solution:



  1. Don't use strings as numbers. Sure, it might work right now because division can't concatenate strings like addition can, but it is a dangerous habit to get into.

  2. There is no need to use a regular expression in this case to split the input into rows and columns. .split(/n/) is the same as .split('n').


  3. (d, v, i, line) is a lot of parameters, in this case you don't need two of them. Instead of line, you can just use row, and you never used i anyways.

  4. Don't default to reduce, the original function can be easily simplified by using map instead and just dropping the diff parameter.

  5. Try to avoid meaningless variable names. For very simple functions, it is fine to just use a, and b, but for anything longer than a line (and even some functions of only one line) it makes the code much more difficult to scan when another programmer in 6 months (you) looks at it.


Here is how I would implement the solution (assuming a relatively small table, if the table is very large, some optimization would be a good idea).






const INPUT = `5t9t2t8
9t4t7t3
3t8t6t5`;

// Contained in most FP libraries, but simple to write
const unary = fn => arg => fn(arg)

const sum = (a, b) => a + b
const isNot = a => b => a !== b
const isDivisible = dividend => divisor => dividend % divisor === 0;

/**
* Takes an array of numbers, returns the result of the division
* of the first two numbers which divide evenly or 0 if no two
* numbers are divisible.
*/
const divideEvenly = numbers =>
return numbers.reduce((carry, n) =>
if (carry) return carry;

const divisor = numbers
.filter(isNot(n))
.find(isDivisible(n));
return divisor == null ? carry : n / divisor;
, 0);


// Without unary, parseInt would fail due to trying to parse with different bases
const solution = INPUT.split('n')
.map(line => line.split('t').map(unary(parseInt)))
.map(divideEvenly)
.reduce(sum, 0);

console.log("solution ", solution);








const INPUT = `5t9t2t8
9t4t7t3
3t8t6t5`;

// Contained in most FP libraries, but simple to write
const unary = fn => arg => fn(arg)

const sum = (a, b) => a + b
const isNot = a => b => a !== b
const isDivisible = dividend => divisor => dividend % divisor === 0;

/**
* Takes an array of numbers, returns the result of the division
* of the first two numbers which divide evenly or 0 if no two
* numbers are divisible.
*/
const divideEvenly = numbers =>
return numbers.reduce((carry, n) =>
if (carry) return carry;

const divisor = numbers
.filter(isNot(n))
.find(isDivisible(n));
return divisor == null ? carry : n / divisor;
, 0);


// Without unary, parseInt would fail due to trying to parse with different bases
const solution = INPUT.split('n')
.map(line => line.split('t').map(unary(parseInt)))
.map(divideEvenly)
.reduce(sum, 0);

console.log("solution ", solution);





const INPUT = `5t9t2t8
9t4t7t3
3t8t6t5`;

// Contained in most FP libraries, but simple to write
const unary = fn => arg => fn(arg)

const sum = (a, b) => a + b
const isNot = a => b => a !== b
const isDivisible = dividend => divisor => dividend % divisor === 0;

/**
* Takes an array of numbers, returns the result of the division
* of the first two numbers which divide evenly or 0 if no two
* numbers are divisible.
*/
const divideEvenly = numbers =>
return numbers.reduce((carry, n) =>
if (carry) return carry;

const divisor = numbers
.filter(isNot(n))
.find(isDivisible(n));
return divisor == null ? carry : n / divisor;
, 0);


// Without unary, parseInt would fail due to trying to parse with different bases
const solution = INPUT.split('n')
.map(line => line.split('t').map(unary(parseInt)))
.map(divideEvenly)
.reduce(sum, 0);

console.log("solution ", solution);






share|improve this answer













share|improve this answer



share|improve this answer











answered Jan 7 at 2:40









Gerrit0

2,6701518




2,6701518











  • "There is no need to use a regular expression" - why would you discourage from using regex? Are they slower or less declarative?
    – thadeuszlay
    Jan 7 at 13:57










  • @thadeuszlay Regex is generally slower, yes, but I wouldn't worry about that here. The reason I recommend just using a string is that regex is such a powerful tool that really isn't necessary here. If you needed to match multiple combinations, using regex is absolutely the way to go, but for just a single character, or a simple sequence of characters, it is easier to just use a string. It is kind of like importing jQuery just to use $('p').remove() once in your code.
    – Gerrit0
    Jan 7 at 19:17










  • I don't get why the unary function is needed. I know that without it wouldn't work properly. But this works without the unary function const parse = line => line.split('t') .map(toInt);
    – thadeuszlay
    Jan 13 at 10:22










  • You can write everything without the unary function, true but it often results in cleaner code as you can avoid functions whose sole purpose is to call another function with one argument.
    – Gerrit0
    Jan 13 at 17:05
















  • "There is no need to use a regular expression" - why would you discourage from using regex? Are they slower or less declarative?
    – thadeuszlay
    Jan 7 at 13:57










  • @thadeuszlay Regex is generally slower, yes, but I wouldn't worry about that here. The reason I recommend just using a string is that regex is such a powerful tool that really isn't necessary here. If you needed to match multiple combinations, using regex is absolutely the way to go, but for just a single character, or a simple sequence of characters, it is easier to just use a string. It is kind of like importing jQuery just to use $('p').remove() once in your code.
    – Gerrit0
    Jan 7 at 19:17










  • I don't get why the unary function is needed. I know that without it wouldn't work properly. But this works without the unary function const parse = line => line.split('t') .map(toInt);
    – thadeuszlay
    Jan 13 at 10:22










  • You can write everything without the unary function, true but it often results in cleaner code as you can avoid functions whose sole purpose is to call another function with one argument.
    – Gerrit0
    Jan 13 at 17:05















"There is no need to use a regular expression" - why would you discourage from using regex? Are they slower or less declarative?
– thadeuszlay
Jan 7 at 13:57




"There is no need to use a regular expression" - why would you discourage from using regex? Are they slower or less declarative?
– thadeuszlay
Jan 7 at 13:57












@thadeuszlay Regex is generally slower, yes, but I wouldn't worry about that here. The reason I recommend just using a string is that regex is such a powerful tool that really isn't necessary here. If you needed to match multiple combinations, using regex is absolutely the way to go, but for just a single character, or a simple sequence of characters, it is easier to just use a string. It is kind of like importing jQuery just to use $('p').remove() once in your code.
– Gerrit0
Jan 7 at 19:17




@thadeuszlay Regex is generally slower, yes, but I wouldn't worry about that here. The reason I recommend just using a string is that regex is such a powerful tool that really isn't necessary here. If you needed to match multiple combinations, using regex is absolutely the way to go, but for just a single character, or a simple sequence of characters, it is easier to just use a string. It is kind of like importing jQuery just to use $('p').remove() once in your code.
– Gerrit0
Jan 7 at 19:17












I don't get why the unary function is needed. I know that without it wouldn't work properly. But this works without the unary function const parse = line => line.split('t') .map(toInt);
– thadeuszlay
Jan 13 at 10:22




I don't get why the unary function is needed. I know that without it wouldn't work properly. But this works without the unary function const parse = line => line.split('t') .map(toInt);
– thadeuszlay
Jan 13 at 10:22












You can write everything without the unary function, true but it often results in cleaner code as you can avoid functions whose sole purpose is to call another function with one argument.
– Gerrit0
Jan 13 at 17:05




You can write everything without the unary function, true but it often results in cleaner code as you can avoid functions whose sole purpose is to call another function with one argument.
– Gerrit0
Jan 13 at 17:05












 

draft saved


draft discarded


























 


draft saved


draft discarded














StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f184476%2fadvent-of-code-2017-day-2-2-in-functional-programming-fp%23new-answer', 'question_page');

);

Post as a guest













































































Popular posts from this blog

Greedy Best First Search implementation in Rust

Function to Return a JSON Like Objects Using VBA Collections and Arrays

C++11 CLH Lock Implementation