34
\$\begingroup\$

Disarium Dilemma

A Disarium is defined as a number whose:

sum of its digits powered with their respective position is equal to the original number


Your Task:

You have a strange obsession with numbers classified as being a disarium. The need to follow the ways of disarium is so great in you that you refuse to read any non-disarium numbered pages in any given book. You have two BIG problems:

  1. Your professor just assigned you to read your textbook from page n to page m
  2. You hit your head really hard last week and can't seem to remember how to programmatically determine if a number is considered to be a disarium.

Time is of the essence so the code to determine the pages you will need to read needs to be as short as possible.

You need to identify all of the disarium within an inclusive range of n through m.

Examples of a disarium:

89 = 81 + 92

135 = 11 + 32 + 53

518 = 51 + 12 + 83

This is code-golf, so the least number of bytes wins!

Here is the full sequence of A032799.

\$\endgroup\$
9
  • \$\begingroup\$ @Fatalize The range is inclusive, I will edit the question to reflect this. \$\endgroup\$
    – CraigR8806
    Jan 19, 2017 at 13:51
  • \$\begingroup\$ Are there any guaranteed bounds on n and m? There’s a very big disarium (12157692622039623539), should answers be able to identify it? \$\endgroup\$
    – Lynn
    Jan 19, 2017 at 15:12
  • \$\begingroup\$ @Lynn Given that there are already a number of solutions, I would say there should be no bounds on the range. \$\endgroup\$
    – CraigR8806
    Jan 19, 2017 at 15:17
  • 2
    \$\begingroup\$ @Lynn. There is no disarium >22 digits, so in a way the range is already bounded. \$\endgroup\$ Jan 19, 2017 at 16:21
  • 3
    \$\begingroup\$ @MistahFiggins Please go to the OEIS link at the bottom of the question. You will find a proof that shows the Disarium sequence is indeed finite. \$\endgroup\$
    – CraigR8806
    Jan 19, 2017 at 20:58

41 Answers 41

11
\$\begingroup\$

Perl 6, 40 39 bytes

{grep {$_==sum .comb Z**1..*},$^a..$^b}

Try it online!

How it works

{                                     }  # A lambda.
                              $^a..$^b   # Range between the two lambda arguments.
 grep {                     },           # Return numbers from that range which satisfy:
               .comb Z  1..*             #  Digits zipped with the sequence 1,2,3,...,
                      **                 #  with exponentiation operator applied to each pair,
           sum                           #  and those exponents summed,
       $_==                              #  equals the number.
\$\endgroup\$
8
\$\begingroup\$

Python2, 98 89 88 84 bytes

lambda n,m:[x for x in range(n,m+1)if sum(int(m)**-~p for p,m in enumerate(`x`))==x]

Horrible. Will get shorter. Starting to look better

Here's my recursive attempt (86 bytes):

f=lambda n,m:[]if n>m else[n]*(sum(int(m)**-~p for p,m in enumerate(`n`))==n)+f(n+1,m)

Thanks to @Rod for saving 4 bytes! range to enumerate and so on.

\$\endgroup\$
1
  • \$\begingroup\$ switching to enumerate, you can use int(n) instead int(`x`[p]) \$\endgroup\$
    – Rod
    Jan 19, 2017 at 14:41
7
\$\begingroup\$

JavaScript (ES7), 105 91 89 88 83 79 82 81 bytes

Thanks to Arnauld for saving 20B, and ETHProductions for saving 6B!

a=>b=>[...Array(b).keys()].filter(c=>c>=a&([...c+''].map(d=>c-=d**++e,e=0),!c))

Usage

Assign the function to a variable, and give it the minimum and the maximum as arguments. Example:

f=a=>b=>[...Array(b).keys()].filter(c=>c>=a&([...c+''].map(d=>c-=d**++e,e=0),!c))
f(0)(90)

Output

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 89]

Further golfing

This seems pretty well-golfed, but there's always room for improvement... I think.

\$\endgroup\$
13
  • \$\begingroup\$ Yeah, that's actually quite a bit shorter. Thanks! \$\endgroup\$
    – Luke
    Jan 19, 2017 at 14:05
  • 1
    \$\begingroup\$ You can change d**(e+1) to d**-~e to save two bytes. \$\endgroup\$ Jan 19, 2017 at 14:10
  • \$\begingroup\$ Thanks for the tip, added it. Only 2 more bytes before we've beaten Python... \$\endgroup\$
    – Luke
    Jan 19, 2017 at 14:19
  • \$\begingroup\$ You can use & instead of &&. One more byte to go... \$\endgroup\$
    – Arnauld
    Jan 19, 2017 at 14:23
  • \$\begingroup\$ I just changed that in my local copy... Guess you were faster. \$\endgroup\$
    – Luke
    Jan 19, 2017 at 14:24
6
\$\begingroup\$

Python 3, 100 bytes

lambda n,m:{*range(10),89,135,175,518,598,1306,1676,2427,2646798,0xa8b8cd06890f2773}&{*range(n,m+1)}

Not the shortest approach, but a pretty cute one. There are finitely many disariums; see the OEIS page for a nice proof. These are all of them.

\$\endgroup\$
2
  • \$\begingroup\$ This is use of hard-coding which is a loophole meta.codegolf.stackexchange.com/a/1063/55243 I would recommended you change your answer to fit with the standard rules \$\endgroup\$
    – george
    Jan 19, 2017 at 16:13
  • 5
    \$\begingroup\$ I don't think this violates the hard-coding rule, as the program still "does work" and the output is not hard-coded. \$\endgroup\$ Jan 19, 2017 at 16:21
6
\$\begingroup\$

JavaScript (Firefox 52+), 68 bytes

f=(n,m)=>(e=0,[for(d of t=n+'')t-=d**++e],t||alert(n),n-m&&f(n+1,m))

Recursive function that outputs via alert. Works in the Developer Edition of Firefox, which you can download on this page. Previous versions of Firefox don't support the ** operator, and no other browser supports [for(a of b)c] syntax.

Test snippet

This uses .map instead of an array comprehension, and Math.pow instead of **, so it should work in all browsers that support ES6.

f=(n,m)=>(e=0,[...t=n+''].map(d=>t-=Math.pow(d,++e)),t||alert(n),n-m&&f(n+1,m))

f(0,100)

\$\endgroup\$
6
\$\begingroup\$

05AB1E, 12 bytes

Saved 2 bytes thanks to Emigna

ŸvygLySmOyQ—

Try it online!

Ÿ            # push [a .. b]
 vy          # for each
   gL        # push [1 .. num digits]
     yS      # push [individual digits]
       m     # push [list of digits to the power of [1..num digits] ]
        O    # sum
         yQ— # print this value if equal
\$\endgroup\$
1
  • \$\begingroup\$ ŸvygLySmOyQ— should work for 12 bytes. \$\endgroup\$
    – Emigna
    Jan 19, 2017 at 16:00
6
\$\begingroup\$

Perl, 43 bytes

map{say if$_==eval s/./+$&**$+[0]/gr}<>..<>

Try it online!

Regex is really powerful, you guys.

Explanation

The first thing the code does is read two integers as input via <>, and creates a range from the first to the second with ... It then uses the standard map function to iterate through this range, and applies the following code to each value: say if$_==eval s/./+$&**$+[0]/gr. This looks like gibberish, and it kind of is, but here's what's really happening.

map implicitly stores its current value in the variable $_. Many perl functions and operations use this value when none is given. This includes regular expressions, such as the s/// substitution operator.

There are four parts to a substitution regex:

  1. String to be manipulated. Ordinarily, the operator =~ is used to apply a regex to a string, but if this operator is absent, then the regex is applied to the implicit variable $_, which contains our current number via the map function.
  2. String to search for. In this case, we're searching for any single non-newline character, denoted by the wildcard .. In effect, we're capturing each individual digit.
  3. String to replace with. We're substituting a plus sign + followed by a mathematical expression, mixed in with some magical Perl variables that make everything significantly easier.

The special scalar variable $& always contains the entirety of the last successful regex capture, which in this case is a single digit. The special array variable @+ always contains a list of postmatch offsets for the last successful match, i.e. the index of the text after the match. $+[0] is the index in $_ of the text immediately following $&. In the case of 135, we capture the digit 1, and the index in 135 of the text immediately afterwards (namely, 35) is 1, which is our exponent. So, we want to raise $& (1) to the power of $+[0] (1) and get 1. We want to raise 3 to the power of 2 and get 9. We want to raise 5 to the power of 3 and get 125.

If the input was 135, the resulting string is +1**1+3**2+5**3.

  1. Regex-modifying flags. Here we're using two regex flags -- /g and /r. /g tells the interpreter to continue replacements after the first is found (otherwise we'd end up with +1**135). /r tells the interpreter not to modify the original string, and instead return what the string would be after the replacements. This is important, because otherwise, it would overwrite $_, and we need it for comparison purposes.

Once the entire substitution is done, we get a mathematical expression, which is evaluated with the eval function. +1**1+3**2+5**3 is evaluated into 1 + 9 + 125 = 135, which is compared to the original number 135. Since these two are equal, the code prints the number.

\$\endgroup\$
2
  • \$\begingroup\$ Beautiful solution. (Note that this won't work is the first input is 0, but I'm not sure it matters). A few bytes to golf: map$_-eval s/./+$&**$+[0]/gr||say,<>..<> \$\endgroup\$
    – Dada
    Jan 22, 2017 at 21:50
  • \$\begingroup\$ And "@+" is 1 byte shorter than $+[0] :) \$\endgroup\$
    – Dada
    Jan 22, 2017 at 22:15
4
\$\begingroup\$

R, 100 bytes

function(n,m,x=n:m)x[sapply(x,function(y)sum(as.integer(el(strsplit(c(y,""),"")))^(1:nchar(y)))==y)]

Unnamed function that takes n and m. As always in R, splitting integers into a numeric digit vector is tedious and eats up a lot of bytes. This makes the function relatively slow and only works for 32-bit integers.

\$\endgroup\$
0
4
\$\begingroup\$

Jelly, 11 bytes

D*J$S⁼
rÇÐf

Try it online!

Got this down from 16 to 11, with some help from @miles!

Explanation:

rÇÐf    Main link, arguments are m and n
r       Generate a list from m to n
 Ç      Invoke the helper link
  Ðf    And filter out all that don't return 1 on that link

D*J$S⁼  Helper link, determines if item is Disarium
D       Break input (the current item of our list in Main) into digits (135 --> [1, 3, 5])
  J$    Create a range from 1 to x, where x is the number of digits             [1, 2, 3]
 *      Raise each digit to the power of their respective index 
    S⁼  And return a 1 if the sum of powers is equal to the helper-link's input
\$\endgroup\$
2
  • \$\begingroup\$ You can use J to get indices. A shorter way might be D*J$S⁼ to combine your two links into one \$\endgroup\$
    – miles
    Jan 19, 2017 at 14:00
  • \$\begingroup\$ Arrived at exactly that conclusion about 20 sec ago. Thnx! \$\endgroup\$
    – steenbergh
    Jan 19, 2017 at 14:02
3
\$\begingroup\$

CJam, 23 bytes

q~),\>{_Ab_,,:).#:+=},p

Try it online!

Explanation

q~                      Get and eval all input
  ),\>                  Get the range between m and n, inclusive
      {                 For each number in the range...
       _Ab               Duplicate and get the list of digits
          _,,:)          Duplicate the list, take its length, make the range from 1 to length
               .#        Vectorize with exponentiation; computes first digit^1, second^2, etc
                 :+      Sum the results
                   =     Compare to the original number
                    },  Filter the range to only numbers for which the above block is true
                      p Print nicely
\$\endgroup\$
3
\$\begingroup\$

05AB1E, 18 bytes

Ÿvy©SDgLsmO®Qi®}})

Try it online!

\$\endgroup\$
3
\$\begingroup\$

Python 2.X, 92 bytes

lambda m,n:[k for k in range(m,n+1)if sum(int(j)**(i+1) for i,j in enumerate(list(`k`)))==k]
\$\endgroup\$
3
  • \$\begingroup\$ Useless whitespace after (i+1), but this is not a problem, when you get rid of the parentheses by doing -~i. \$\endgroup\$
    – Yytsi
    Jan 19, 2017 at 15:26
  • \$\begingroup\$ That'd make my attempt exact same as yours! \$\endgroup\$
    – hashcode55
    Jan 19, 2017 at 17:44
  • \$\begingroup\$ Almost. You have list('k'), which I don't have. However, you can still remove the whitespace :) \$\endgroup\$
    – Yytsi
    Jan 19, 2017 at 18:48
3
\$\begingroup\$

Python 2, 84 bytes

A full program approach, currently the same length as the lambda solution.

a,b=input()
while a<=b:
 t=p=0
 for x in`a`:p+=1;t+=int(x)**p
 if t==a:print a
 a+=1

Try it online!

\$\endgroup\$
1
  • \$\begingroup\$ Hmm. I thought about the almost exact answer, but discarded due to confusion with input(). Very nice! +1. \$\endgroup\$
    – Yytsi
    Jan 19, 2017 at 20:50
3
\$\begingroup\$

Japt, 15 bytes

òV f_¥Zì £XpYÄÃx

Test it online! This was a collaboration between @obarakon and myself.

How it works

òV f_¥Zì £XpYÄÃx   // Implicit: U, V = input integers
òV                 // Create the inclusive range [U...V].
   f_              // Filter to only the items Z where...
               x   //   the sum of
      Zì           //   the decimal digits of Z,
         £XpYÄÃ    //   where each is raised to the power of (index + 1),
     ¥             //   is equal to Z.
                   // Implicit: output result of last expression

In the latest version of Japt, x accepts a function as an argument, which allows us to golf another byte:

òV f_¥Zì x@XpYÄ

Test it online!

\$\endgroup\$
3
\$\begingroup\$

05AB1E, 8 bytes

ŸʒDSāmOQ

Try it online!

\$\endgroup\$
2
\$\begingroup\$

Clojure, 107 bytes

#(for[i(range %(inc %2)):when(=(int(apply +(map(fn[i v](Math/pow(-(int v)48)(inc i)))(range)(str i))))i)]i)

Implementing the equation is terribly long.

\$\endgroup\$
1
  • \$\begingroup\$ can save a couple of bytes by doing (.pow(-(int v)48M) \$\endgroup\$
    – cliffroot
    Jan 30, 2017 at 15:17
2
\$\begingroup\$

TI-Basic, 85 bytes

Input 
For(I,X,Y
If I<=9 or sum(I={89,135,175,518,598,1306,1676,2427,2646798,12157692622039623539
Disp I
End
\$\endgroup\$
4
  • \$\begingroup\$ I did not know hard-coding was permitted. :) \$\endgroup\$
    – Abel Tom
    Jan 19, 2017 at 15:58
  • \$\begingroup\$ @AbelTom Well, it really helps that this series only has 20 terms. Also, converting number to string in TI-Basic takes lots of bytes. Only other solution would be to int(log( every number and then do the powers. Perhaps this is shorter, but I doubt it. \$\endgroup\$
    – Timtech
    Jan 19, 2017 at 16:14
  • \$\begingroup\$ That input method is very clever but kind of sketchy. You need to be in FUNC mode and the window has to be set up to include your input point. Doesn't seem portable enough to me. \$\endgroup\$
    – Jakob
    Jan 19, 2017 at 20:48
  • \$\begingroup\$ @JakobCornell By default the calc is in FUNC mode, although I do see what you're saying about the input resolution. But, this method is pretty common in golfing. You could always Prompt X,Y instead. \$\endgroup\$
    – Timtech
    Jan 20, 2017 at 22:13
2
\$\begingroup\$

Haskell, 61 bytes

n#m=[i|i<-[n..m],i==sum(zipWith(^)(read.pure<$>show i)[1..])]

Usage example 5 # 600 -> [5,6,7,8,9,89,135,175,518,598].

Check each number i in the range [n..m]. The digits are extracted by turning i into a string (show) and making each char a one element string (pure) which is turned into an integer again (read). Zip those numbers element wise with [1..] via the function ^ and take the sum.

\$\endgroup\$
2
\$\begingroup\$

PHP, 92 91 88 bytes

3 bytes saved thanks @AlexHowansky

for([,$n,$m]=$argv;$n<=$m;$s-$n++?:print"$s,")for($i=$s=0;_>$b=($n._)[$i++];)$s+=$b**$i;

takes input from command line arguments; prints a trailing comma. Run with -r.

\$\endgroup\$
5
  • 1
    \$\begingroup\$ Save three with for([,$n,$m]=$argv;$n<=$m; \$\endgroup\$ Jan 19, 2017 at 16:31
  • \$\begingroup\$ Strange that print works there but echo doesn't. I guess because echo doesn't return anything -- not even null, oddly. \$\endgroup\$ Jan 19, 2017 at 16:50
  • \$\begingroup\$ @AlexHowansky: It´s also strange that "$n"[index] and "_$n"[index] produce parse errors while "89"[index] and $s="$n";$s[index] are perfectly fine. \$\endgroup\$
    – Titus
    Jan 19, 2017 at 17:17
  • \$\begingroup\$ Hmm yes, that does seem odd at first, but after checking the docs, it appears they do explicitly say that the feature works only for string literals. \$\endgroup\$ Jan 19, 2017 at 17:20
  • \$\begingroup\$ Heh heh well this works, but it probably doesn't save you any bytes: ("_$n")[index] \$\endgroup\$ Jan 19, 2017 at 17:24
2
\$\begingroup\$

Mathematica, 59 bytes

Select[Range@##,Tr[(d=IntegerDigits@#)^Range@Length@d]==#&]&

Unnamed function taking two integer arguments and returning a list of integers. (d=IntegerDigits@#)^Range@Length@d produces the list of digits of a number to the appropriate powers; Tr[...]==# detects whether the sum of those digit-powers equals the original number.

\$\endgroup\$
2
\$\begingroup\$

MATLAB, 88 73 bytes

@(n,m)find(arrayfun(@(n)n==sum((num2str(n)-48).^(1:log10(n)+1)),n:m))+n-1

Original answer:

function g(n,m);a=n:m;a(arrayfun(@(n)n==sum((num2str(n)-'0').^(1:floor(log10(n))+1)),a))

num2str(n)-'0' splits a n into a vector of its digits, and 1:floor(log10(n))+1 is a vector holding one to the number of digits in n. Thanks to log for the golf down to an anonymous function, saving 15 bytes.

\$\endgroup\$
2
\$\begingroup\$

Japt, 12 bytes

òV fȶìxÈpYÄ

Try it

òV fȶìxÈpYÄ     :Implicit input of integers U & V
òV               :Range [U,V]
   f             :Filter by
    È            :Passing each through the following function
     ¶           :  Check for equality with
      ì          :  Convert to digit array
       x         :  Reduce by addition
        È        :  After passing each element at 0-based index Y through the following function
         p       :    Raise to the power of
          YÄ     :    Y+1
\$\endgroup\$
2
\$\begingroup\$

Brachylog, 10 bytes

⟦₂∋.i₁ᶠ^ᵐ+

Try it online!

Generates each disarium through the output variable.

   .          The output variable is
  ∋           an element of
⟦₂            the inclusive range between the elements of the input.
      ᶠ       Find every
    i₁        pair of a digit and its 1-index in the output variable,
       ^ᵐ     and raise each digit to the power of its index.
         +    The sum is equal to the output variable.

Also worth mentioning here, rather than in a comment or its own submission, that steenbergh's Jelly solution can now be golfed down to rD*J$S⁼ƲƇ, but I might find this a bit more idiomatic:

Jelly, 9 bytes

rD*J$SƊƑƇ

Try it online!

\$\endgroup\$
2
\$\begingroup\$

Desmos, 82 bytes

a=[n...m]
d=\floor(\log a)
f(n,m)=a[a=\sum_{i=0}^d\mod(\floor(a/10^i),10)^{d-i+1}]

Try it on Desmos!

\$\endgroup\$
1
\$\begingroup\$

Haskell, 82 76 75 bytes

n!m=[x|x<-[n..m],x==x#(length.show)x]
0#i=0
n#i=(div n 10)#(i-1)+mod n 10^i

Try it online! Usage: 5 ! 175

This checks each number in the range n to m if its a disarium number and is hence quite slow for big m.


Faster version: (93 bytes)

n!m=[x|x<-[0..9]++[89,135,175,518,598,1306,1676,2427,2646798,12157692622039623539],x>=n,x<=m]

Try it online!

\$\endgroup\$
1
\$\begingroup\$

C (gcc), 136 bytes

r[]={0,0};f(n){if(n)f(n/10),r[1]=pow((n%10),*r)+r[1]+.5,r[0]++;else*r=1,r[1]=0;}g(m,x){for(;m<=x;m++){f(m);if(m==r[1])printf("%d,",m);}}

Header defining pow on TIO because for some reason it didn't auto include pow. My computer did, so I'm going to roll with that.

Try it online!

\$\endgroup\$
1
\$\begingroup\$

MATL, 16 bytes

&:"@tFYAtn:^s=?@

Try it online!

&:        % Input two n, m implicitly. Push array [n n+1 ... m]
"         % For each k in that array
  @       %   Push k
  tFYA    %   Duplicate. Convert to decimal digits
  tn:     %   Duplicate. Push [1 2 ... d], where d is the number of digits
  ^       %   Element-wise power
  s       %   Sum of array
  =       %   Compare with previous copy of k: is it equal?
  ?       %   If so
    @     %     Push k
          %   End, implicit
          % End, implicit
          % Display stack, implicit
\$\endgroup\$
1
\$\begingroup\$

Batch, 115 bytes

@for %%d in (0 1 2 3 4 5 6 7 8 9 89 135 175 518 598 1306 1676 2427 2646798)do @if %%d geq %1 if %%d leq %2 echo %%d

Batch only has 32-bit arithmetic which has no way of comparing the last disarium number, but if you insist on string comparisons, then for 402 bytes:

@echo off
for %%d in (0 1 2 3 4 5 6 7 8 9 89 135 175 518 598 1306 1676 2427 2646798 12157692622039623539)do call:c %1 %%d&&call:c %%d %2&&echo %%d
exit/b
:c
call:p %1 %2
set r=%s%
call:p %2 %1
:g
if %r:~,1% lss %s:~,1% exit/b0
if %r:~,1% gtr %s:~,1% exit/b1
if %r%==%s% exit/b0
set r=%r:~1%
set s=%s:~1%
goto g
:p
set s=%1
set t=%2
:l
set s=0%s%
set t=%t:~1%
if not "%t%"=="" goto l
\$\endgroup\$
1
\$\begingroup\$

Python 2, 100 bytes

for i in range(input(),input()+1):x=sum(int(`i`[n])**-~n for n in range(len(`i`)));print("",x)[x==i]

I haven't had a chance to run this yet (doing this on my phone).

\$\endgroup\$
10
  • \$\begingroup\$ This doesn't work. Incorrect syntax and when corrected, would print only boolean values. Starts from the exponent 0, which is also incorrect. Also, you don't need the square brackets inside sum. \$\endgroup\$
    – Yytsi
    Jan 19, 2017 at 14:37
  • \$\begingroup\$ This isn't checking for disarium numbers. \$\endgroup\$
    – hashcode55
    Jan 19, 2017 at 14:52
  • \$\begingroup\$ @hashcode55, fixed (?) \$\endgroup\$
    – Daniel
    Jan 19, 2017 at 14:58
  • \$\begingroup\$ @TuukkaX, now it should work I think \$\endgroup\$
    – Daniel
    Jan 19, 2017 at 14:59
  • \$\begingroup\$ I'm not on computer, but this should print a newline on each iteration, where i is a Disarium. I have no idea whether this is allowed, but I would say no, since the output gets very blank. \$\endgroup\$
    – Yytsi
    Jan 19, 2017 at 15:04
1
\$\begingroup\$

Scala, 132 129 bytes

(% :Int,^ :Int)=>for(i<- %to^)if(((0/:(i+"").zipWithIndex)((z,f)=>{z+BigInt(f._1.toInt-48).pow(f._2+1).intValue}))==i)println(i)

129 edit: Changing the for loop's variable name from & to i saved three spaces.


Explanation

For each value in the input range:

  • convert it to a string with +""
  • use zipWithIndex to produce a list of tuples containing a char of the digit and its index
  • fold the list by returning each char's int value minus 48 (lines up to 0-9) to the power of its list index plus one (to start at ^1)
  • if the result matches the input, print it

Comments

Finally got around to learning how fold and zipWithIndex work. I'm unhappy with the int conversions, but I am pleased with the succinctness of fold and zipWithIndex.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.