Narcissistic decimal number: Difference between revisions

m
→‎{{header|AppleScript}}: Idiomatic version rewritten with more efficient digit group generation.
m (→‎{{header|AppleScript}}: Idiomatic version: added comment.)
m (→‎{{header|AppleScript}}: Idiomatic version rewritten with more efficient digit group generation.)
Line 432:
===Idiomatic===
 
This script and earlier versions were written from scratch in AppleScript, andthis returnone returning the required 25 numbers in aroundjust under a quartersixth of a second. (The extreme slowness of the JavaScript/Haskell translation above is certainly ''not'' due to AppleScript being "a little out of its depth here"!) This version actually ''does'' contain a "hand optimisation" which, for speed, limits the lengths of the temporary lists used.The Ithandler nowbelow returns the first 41 numbers in around sevenfour-and-a half seconds, the first 42 in fortytwenty-six secondsnine, and the first 44 in twoone minutesminute fiftyforty-seven. (All timings on a 3.4 GHz iMac.) The 43rd and 44th numbers are both displayed in Script Editor's result pane as 4.33828176939137E+15, but appear to have the correct values when tested. The narcissistic decimal numbers beyond these are admittedly beyond the resolution of AppleScript's number classes.
 
TheAt the time of writing, the JavaScript/Haskell translation above doesn'tstill returnonly thereturns first so many narcissistic decimal20 numbers,. butTo thoseget with upit to soreturn manythe digits.required As such25, ita doesn'tuser strictly conform toof the task description. Itcode would onlyhave returnto theknow requiredin 25 numbersadvance becausethat the 25th narcissistic decimal number also happens to be the last of four withwhich have 7 digits. A user of the code would need to know this in advance to be able to supply the relevant parameter. However, as currently presented, the code still only returns 20 numbers.
 
<lang applescript>(*
Line 440:
(or as many of the q as can be represented by AppleScript number values).
*)
 
on narcissisticDecimalNumbers(q)
script o
property output : {}
--property "DSN"m is: a0 convenience-- termDigits for aper collection/number used to store its digits.
property previousDSNsdone : missing valuefalse
property newDSNs : missing value
-- Recursive subhandler. Builds lists containing m digit values while summing the digits' mth powers.
-- Since previousDSNs and newDSNs will be potentially *very* long lists,
on recurse(digitList, sumOfPowers, digitShortfall)
-- their contents are handled here as sublists of 1000 each.
-- If m digits have been obtained, compare the sum of powers's digits with the values in the list.
property previousSublist : missing value
-- Otherwise continue branching the recursion to derive longer lists.
property newSublist : missing value
if (digitShortfall is 0) then
end script
set temp to sumOfPowers
if (q > 89) then set q to 89 -- Number of narcissistic decimal integersset knownunmatched to exist.m
repeat until (temp = 0)
set maxM to 16 -- Maximum number of decimal digits (other than trailing zeros) in AppleScript numbers.
set sumDigit to temp mod 10
if (sumDigit is in digitList) then
-- Begin with single-digit values, which are narcissistic by definition.
repeat with id from 01 to 9unmatched
if (inumber d q)of thendigitList return= o'ssumDigit) outputthen
set endnumber d of o's outputdigitList to imissing value
set unmatched to unmatched - 1
end repeat
-- Main loop, per increase in digits/number:
-- Tests digit collections rather than successive integer values, but happens to turn up the numbers in order.
set m to 1 -- Digits/number.
set o's newDSNs to {rest of o's output} -- Initial DSNs. (1-9.)
repeat until (m = maxM) -- or until returning from the handler with q results.
set m to m + 1
set o's previousDSNs to o's newDSNs
set o's newSublist to {}
set o's newDSNs to {o's newSublist}
repeat with g from 1 to (count o's previousDSNs)
set o's previousSublist to item g of o's previousDSNs
repeat with i from 1 to (count o's previousSublist)
set thisDSN to item i of o's previousSublist
-- Base number for further DSNs to be derived from this one.
set baseDSN to thisDSN * 10
-- Extract this one's digits, subtotalling the sum of their current-mth powers.
set baseDigits to {}
set subtotal to 0
repeat until (thisDSN = 0)
set thisDigit to thisDSN mod 10
set end of baseDigits to thisDigit
set subtotal to subtotal + thisDigit ^ m
set thisDSN to thisDSN div 10
end repeat
-- Derive and test new digit groups having an additional digit each, only adding values
-- up to and including the old DSN's LSD to ensure every group at this level is unique.
repeat with additionalDigit from 0 to (beginning of baseDigits)
set end of o's newSublist to baseDSN + additionalDigit
-- Start a new newSublist if this one reaches 1000 items.
if ((count o's newSublist) is 1000) then
set o's newSublist to {}
set end of o's newDSNs to o's newSublist
end if
set thisGroup to baseDigits & additionalDigit
-- Complete the sum-of-powers calculation for this group.
set sumResult to subtotal + additionalDigit ^ m
-- Compare the result's digits with those in the group list,
-- eliminating matches from the list one-for-one.
set temp to sumResult
repeat until (temp = 0)
set thisDigit to temp mod 10
if (thisDigit is not in thisGroup) then exit repeat
repeat with groupDigit in thisGroup
if (groupDigit's contents = thisDigit) then
set groupDigit's contents to missing value
exit repeat
end if
end repeat
set temp to temp div 10else
end exit repeat
-- If this digit group's members have all been matched and replaced, the sum-of-powers result is narcissistic.
if ((count thisGroup's numbers) = 0) then
set end of o's output to sumResult div 1
-- If it's the qth find, return all q results.
if ((count o's output) = q) then return o's output
end if
set temp to temp div 10
end repeat
-- If all the digits have been matched, the sum of powers is narcissistic.
end repeat
if (unmatched is 0) then
set end of my output to sumOfPowers div 1
-- If it's the qth find, signal the end of the process.
if ((count my output) = q) then set done to true
end if
else
-- If fewer than m digits at this level, derive longer lists from the current one.
-- Adding only values that are less than or equal to the last one makes each
-- collection unique and turns up the narcissistic numbers in numerical order.
repeat with additionalDigit from 0 to end of digitList
recurse(digitList & additionalDigit, sumOfPowers + additionalDigit ^ m, digitShortfall - 1)
if (done) then exit repeat
end repeat
end if
end recurse
end script
(* Outer handler code. *)
if (q > 89) then set q to 89 -- Number of narcissistic decimal integers known to exist.
set maxM to 16 -- Maximum number of decimal digits (other than trailing zeros) in AppleScript numbers.
tell o
-- Begin with zero, which is narcissistic by definition and is never the only digit used in other numbers.
if (q > 0) then set end of its output to 0
if (q < 2) then set its done to true
-- Initiate the recursive building and testing of collections of increasing numbers of digit values.
repeat until (its done)
set its m to (its m) + 1
if (its m > maxM) then
set end of its output to "Remaining numbers beyond AppleScript's number precision"
set its done to true
else
repeat with digit from 1 to 9
recurse({digit}, digit ^ (its m), (its m) - 1)
if (its done) then exit repeat
end repeat
end if
end repeat
end repeat
return its output
end tell
-- If we're here, the repeat reached maxM.
return o's output & {"Remaining numbers beyond AppleScript's number precision"}
end narcissisticDecimalNumbers
 
-- Demo:
return narcissisticDecimalNumbers(25)</lang>
 
557

edits