RosettaCodeData/Task/Narcissistic-decimal-number/JavaScript/narcissistic-decimal-number-4.js

145 lines
3.9 KiB
JavaScript
Raw Permalink Normal View History

2017-09-23 10:01:46 +02:00
(() => {
'use strict';
2020-02-17 23:21:07 -08:00
// main :: IO ()
const main = () =>
console.log(
fTable(
'Narcissistic decimal numbers of lengths [1..7]:\n'
)(show)(show)(
narcissiOfLength
)(enumFromTo(1)(7))
);
2017-09-23 10:01:46 +02:00
// narcissiOfLength :: Int -> [Int]
const narcissiOfLength = n =>
2020-02-17 23:21:07 -08:00
0 < n ? filter(isDaffodil(n))(
digitPowerSums(n)
) : [0];
2017-09-23 10:01:46 +02:00
2020-02-17 23:21:07 -08:00
// powerSum :: Int -> [Int] -> Int
const powerSum = n =>
xs => xs.reduce(
(a, x) => a + pow(x, n), 0
);
// isDaffodil :: Int -> Int -> Bool
const isDaffodil = e => n => {
// True if the decimal digits of N,
// each raised to the power E, sum to N.
const ds = digitList(n);
return e === ds.length && n === powerSum(e)(ds);
};
2017-09-23 10:01:46 +02:00
// The subset of integers of n digits that actually need daffodil checking:
// (Flattened leaves of a tree of unique digit combinations, in which
// order is not significant. Digit sequence doesn't affect power summing)
// digitPowerSums :: Int -> [Int]
const digitPowerSums = nDigits => {
const
2020-02-17 23:21:07 -08:00
digitPowers = map(x => [x, pow(x, nDigits)])(
enumFromTo(0)(9)
),
treeGrowth = (n, parentPairs) => 0 < n ? (
2017-09-23 10:01:46 +02:00
treeGrowth(n - 1,
isNull(parentPairs) ? (
digitPowers
2020-02-17 23:21:07 -08:00
) : concatMap(
([parentDigit, parentSum]) =>
2017-09-23 10:01:46 +02:00
map(([leafDigit, leafSum]) => //
2020-02-17 23:21:07 -08:00
[leafDigit, parentSum + leafSum])(
take(parentDigit + 1)(digitPowers)
)
)(parentPairs)
)
2017-09-23 10:01:46 +02:00
) : parentPairs;
2020-02-17 23:21:07 -08:00
return map(snd)(treeGrowth(nDigits, []));
2017-09-23 10:01:46 +02:00
};
2020-02-17 23:21:07 -08:00
// ---------------------GENERIC FUNCTIONS---------------------
// enumFromTo :: Int -> Int -> [Int]
const enumFromTo = m => n =>
Array.from({
length: 1 + n - m
}, (_, i) => m + i);
2017-09-23 10:01:46 +02:00
// concatMap :: (a -> [b]) -> [a] -> [b]
2020-02-17 23:21:07 -08:00
const concatMap = f =>
xs => xs.flatMap(f);
2017-09-23 10:01:46 +02:00
// cons :: a -> [a] -> [a]
2020-02-17 23:21:07 -08:00
const cons = x =>
xs => [x].concat(xs);
// digitList :: Int -> [Int]
const digitList = n => {
const go = x => 0 < x ? (
cons(x % 10)(
go(Math.floor(x / 10))
)
) : [];
return 0 < n ? go(n) : [0];
}
2017-09-23 10:01:46 +02:00
// filter :: (a -> Bool) -> [a] -> [a]
2020-02-17 23:21:07 -08:00
const filter = f => xs => xs.filter(f);
2017-09-23 10:01:46 +02:00
// map :: (a -> b) -> [a] -> [b]
2020-02-17 23:21:07 -08:00
const map = f =>
xs => xs.map(f);
2017-09-23 10:01:46 +02:00
// isNull :: [a] -> Bool
2020-02-17 23:21:07 -08:00
// isNull :: String -> Bool
const isNull = xs =>
1 > xs.length;
2017-09-23 10:01:46 +02:00
// length :: [a] -> Int
const length = xs => xs.length;
// pow :: Int -> Int -> Int
2020-02-17 23:21:07 -08:00
const pow = Math.pow;
2017-09-23 10:01:46 +02:00
// take :: Int -> [a] -> [a]
2020-02-17 23:21:07 -08:00
const take = n =>
xs => xs.slice(0, n);
2017-09-23 10:01:46 +02:00
// snd :: (a, b) -> b
2020-02-17 23:21:07 -08:00
const snd = tpl => tpl[1];
// show :: a -> String
const show = x => JSON.stringify(x)
2017-09-23 10:01:46 +02:00
2020-02-17 23:21:07 -08:00
// zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
const zipWith = f => xs => ys =>
xs.slice(
0, Math.min(xs.length, ys.length)
).map((x, i) => f(x)(ys[i]));
2017-09-23 10:01:46 +02:00
2020-02-17 23:21:07 -08:00
// ------------------------FORMATTING-------------------------
2017-09-23 10:01:46 +02:00
2020-02-17 23:21:07 -08:00
// fTable :: String -> (a -> String) -> (b -> String)
// -> (a -> b) -> [a] -> String
const fTable = s => xShow => fxShow => f => xs => {
// Heading -> x display function ->
// fx display function ->
// f -> values -> tabular string
const
ys = xs.map(xShow),
w = Math.max(...ys.map(length));
return s + '\n' + zipWith(
a => b => a.padStart(w, ' ') + ' -> ' + b
)(ys)(
xs.map(x => fxShow(f(x)))
).join('\n');
};
2017-09-23 10:01:46 +02:00
2020-02-17 23:21:07 -08:00
// MAIN ---
return main();
2017-09-23 10:01:46 +02:00
})();