Narcissistic decimal number: Difference between revisions
Content added Content deleted
(→Haskell reduced search: (used swap in digitList)) |
(→JS ES6: -> Generating the unordered digit combinations as their power sums) |
||
Line 1,544: | Line 1,544: | ||
In this way we can find the 25th narcissistic number after '''sum(map(compose(length, digitGroups), enumFromTo(1, 7))) === 19447''' tests – an improvement on the exhaustive trawl through '''9926315''' integers. |
In this way we can find the 25th narcissistic number after '''sum(map(compose(length, digitGroups), enumFromTo(1, 7))) === 19447''' tests – an improvement on the exhaustive trawl through '''9926315''' integers. |
||
(Generating the unordered digit combinations directly as power sums allows faster testing later, and needs less space) |
|||
<lang JavaScript>(() => { |
<lang JavaScript>(() => { |
||
'use strict'; |
'use strict'; |
||
// DAFFODILS -------------------------------------------------------------- |
|||
// GENERIC FUNCTIONS |
|||
// |
// narcissiOfLength :: Int -> [Int] |
||
const |
const narcissiOfLength = n => |
||
n > 0 ? filter(curry(isDaffodil)(n), digitPowerSums(n)) : [0]; |
|||
const lngX = xs.length; |
|||
return (lngX !== ys.length) ? false : ( |
|||
// Do the decimal digits of N, each raised to the power E, sum to N itself ? |
|||
lngX > 0 ? ( |
|||
(() => { |
|||
// isDaffodil :: Int -> Int -> Bool |
|||
let i = lngX; |
|||
const isDaffodil = (e, n) => { |
|||
while (i--) |
|||
const |
|||
if (xs[i] !== ys[i]) return false; |
|||
powerSum = (n, xs) => xs.reduce((a, x) => a + Math.pow(x, n), 0), |
|||
digitList = n => (n > 0) ? ( |
|||
) |
cons((n % 10), digitList(Math.floor(n / 10))) |
||
) |
) : [], |
||
ds = digitList(n); |
|||
return e === ds.length && n === powerSum(e, ds); |
|||
}; |
}; |
||
// The subset of integers of n digits that actually need daffodil checking: |
|||
// concat :: [[a]] -> [a] | [String] -> String |
|||
const concat = xs => { |
|||
// (Flattened leaves of a tree of unique digit combinations, in which |
|||
if (xs.length > 0) { |
|||
// order is not significant. Digit sequence doesn't affect power summing) |
|||
const unit = typeof xs[0] === 'string' ? '' : []; |
|||
return unit.concat.apply(unit, xs); |
|||
// digitPowerSums :: Int -> [Int] |
|||
const digitPowerSums = nDigits => { |
|||
const |
|||
digitPowers = map(x => [x, pow(x, nDigits)], enumFromTo(0, 9)), |
|||
treeGrowth = (n, parentPairs) => (n > 0) ? ( |
|||
treeGrowth(n - 1, |
|||
isNull(parentPairs) ? ( |
|||
digitPowers |
|||
) : concatMap(([parentDigit, parentSum]) => |
|||
map(([leafDigit, leafSum]) => // |
|||
[leafDigit, parentSum + leafSum], |
|||
take(parentDigit + 1, digitPowers) |
|||
), |
|||
parentPairs |
|||
)) |
|||
) : parentPairs; |
|||
return map(snd, treeGrowth(nDigits, [])); |
|||
}; |
}; |
||
// GENERIC FUNCTIONS ------------------------------------------------------ |
|||
// enumFromTo :: Int -> Int -> Maybe Int -> [Int] |
|||
const enumFromTo = (m, n, step) => { |
|||
const d = (step || 1) * (n >= m ? 1 : -1); |
|||
return Array.from({ |
|||
length: Math.floor((n - m) / d) + 1 |
|||
}, (_, i) => m + (i * d)); |
|||
}; |
|||
// concatMap :: (a -> [b]) -> [a] -> [b] |
// concatMap :: (a -> [b]) -> [a] -> [b] |
||
const concatMap = (f, xs) => [].concat.apply([], xs.map(f)); |
const concatMap = (f, xs) => [].concat.apply([], xs.map(f)); |
||
Line 1,578: | Line 1,607: | ||
const cons = (x, xs) => [x].concat(xs); |
const cons = (x, xs) => [x].concat(xs); |
||
// 2 or more arguments |
|||
// curry :: Function -> Function |
// curry :: Function -> Function |
||
const curry = (f, ...args) => { |
const curry = (f, ...args) => { |
||
Line 1,586: | Line 1,616: | ||
return go([].slice.call(args, 1)); |
return go([].slice.call(args, 1)); |
||
}; |
}; |
||
// enumFromTo :: Int -> Int -> [Int] |
|||
const enumFromTo = (m, n) => |
|||
Array.from({ |
|||
length: Math.floor(n - m) + 1 |
|||
}, (_, i) => m + i); |
|||
// filter :: (a -> Bool) -> [a] -> [a] |
// filter :: (a -> Bool) -> [a] -> [a] |
||
const filter = (f, xs) => xs.filter(f); |
const filter = (f, xs) => xs.filter(f); |
||
// |
// map :: (a -> b) -> [a] -> [b] |
||
const |
const map = curry((f, xs) => xs.map(f)); |
||
// isNull :: [a] -> Bool |
// isNull :: [a] -> Bool |
||
const isNull = xs => (xs instanceof Array) ? xs.length < 1 : undefined; |
const isNull = xs => (xs instanceof Array) ? xs.length < 1 : undefined; |
||
// |
// length :: [a] -> Int |
||
const |
const length = xs => xs.length; |
||
// pow :: Int -> Int -> Int |
|||
const pow = Math.pow |
|||
// |
// take :: Int -> [a] -> [a] |
||
const |
const take = (n, xs) => xs.slice(0, n); |
||
// show :: |
// show :: |
||
// (a -> String) f, Num n => |
|||
// a -> maybe f -> maybe n -> String |
|||
const show = JSON.stringify; |
const show = JSON.stringify; |
||
// |
// snd :: (a, b) -> b |
||
const |
const snd = tpl => Array.isArray(tpl) ? tpl[1] : undefined; |
||
// NARCISSI |
|||
// narcissiOfLength :: Int -> [Int] |
|||
const narcissiOfLength = n => { |
|||
const isDaffodil = sortedDigits => |
|||
arrayEq(sortedDigits, sort(digitList(powerSum(n, sortedDigits)))); |
|||
return map(powerSum(n), filter(isDaffodil, digitGroups(n))); |
|||
}; |
|||
// powerSum :: Int -> [Int] -> Int |
|||
const powerSum = curry((n, xs) => |
|||
xs.reduce((a, x) => a + Math.pow(x, n), 0)); |
|||
// Full list of sorted combinations of digits [0..9], with repetition. |
|||
// digitGroups :: Int -> [[Int]] |
|||
const digitGroups = nDigits => { |
|||
const |
|||
digits = enumFromTo(0, 9), |
|||
sortedCombinations = (n, xs) => (n > 0) ? ( |
|||
sortedCombinations(n - 1, |
|||
isNull(xs) ? ( |
|||
map(pure, digits) |
|||
) : concatMap(xxs => |
|||
map(y => cons(y, xxs), enumFromTo(0, head(xxs))), xs |
|||
)) |
|||
) : xs; |
|||
return sortedCombinations(nDigits, []); |
|||
}; |
|||
// digitList :: Int -> [Int] |
|||
const digitList = n => |
|||
(n > 0) ? cons((n % 10), digitList(Math.floor(n / 10))) : []; |
|||
// TEST ------------------------------------------------------------------- |
|||
// return length(concatMap(digitPowerSums, enumFromTo(0, 7))); |
|||
// TEST |
|||
// Narcissistic decimal numbers of digit length from 1 to 7: |
|||
return show( |
return show( |
||
concatMap(narcissiOfLength, enumFromTo(0, 7)) |
|||
); |
); |
||
})();</lang> |
})();</lang> |