Factorials and never ending cycles!

33

3

As you may know it, the factorial of a positive integer n is the product of all the positive integers which are equal or smaller to n.

For instance :

6! = 6*5*4*3*2*1 = 720
0! = 1

We will now define a special operation with an irrelevant name like sumFac:

Given a positive integer n, sumFac(n) is the sum of the factorials of the digits.

For instance :

sumFac(132) = 1! + 3! + 2! = 9

Task

Your mission, whether or not you choose to accept it, is to return the sequence (potentially infinite) of the applications of sumFac to an integer given in input.

Example : 132 -> 132, 9, 362880, 81369, 403927, ...

But that's not all! Indeed, the applications of sumFac will eventually create a cycle. You must also return this cycle!

If your language has a built in factorial you can use it. I'm not picky about the return type, you just have to return the sequence of sumFac applications and the cycle in a format understandable by a human.

EDIT : To help you visualize better what should the output look like I copied Leaky Nun's just below:

[132, 9, 362880, 81369, 403927, 367953, 368772, 51128, 40444, 97, 367920, 368649, 404670, 5810, 40442, 75, 5160, 842, 40346, 775, 10200, 6, 720, 5043, 151, 122, 5, 120, 4, 24, 26, 722, 5044, 169, 363601, 1454]

You just need to stop the sequence when the cycle is about to start for the second time!

But this is code-golf so the shortest answer in bytes wins!

Leaderboard

Here is a Stack Snippet to generate both a regular leaderboard and an overview of winners by language.

/* Configuration */

var QUESTION_ID = 117583; // Obtain this from the url
// It will be like https://XYZ.stackexchange.com/questions/QUESTION_ID/... on any question page
var ANSWER_FILTER = "!t)IWYnsLAZle2tQ3KqrVveCRJfxcRLe";
var COMMENT_FILTER = "!)Q2B_A2kjfAiU78X(md6BoYk";
var OVERRIDE_USER = 68509; // This should be the user ID of the challenge author.

/* App */

var answers = [], answers_hash, answer_ids, answer_page = 1, more_answers = true, comment_page;

function answersUrl(index) {
  return "https://api.stackexchange.com/2.2/questions/" +  QUESTION_ID + "/answers?page=" + index + "&pagesize=100&order=desc&sort=creation&site=codegolf&filter=" + ANSWER_FILTER;
}

function commentUrl(index, answers) {
  return "https://api.stackexchange.com/2.2/answers/" + answers.join(';') + "/comments?page=" + index + "&pagesize=100&order=desc&sort=creation&site=codegolf&filter=" + COMMENT_FILTER;
}

function getAnswers() {
  jQuery.ajax({
    url: answersUrl(answer_page++),
    method: "get",
    dataType: "jsonp",
    crossDomain: true,
    success: function (data) {
      answers.push.apply(answers, data.items);
      answers_hash = [];
      answer_ids = [];
      data.items.forEach(function(a) {
        a.comments = [];
        var id = +a.share_link.match(/\d+/);
        answer_ids.push(id);
        answers_hash[id] = a;
      });
      if (!data.has_more) more_answers = false;
      comment_page = 1;
      getComments();
    }
  });
}

function getComments() {
  jQuery.ajax({
    url: commentUrl(comment_page++, answer_ids),
    method: "get",
    dataType: "jsonp",
    crossDomain: true,
    success: function (data) {
      data.items.forEach(function(c) {
        if (c.owner.user_id === OVERRIDE_USER)
          answers_hash[c.post_id].comments.push(c);
      });
      if (data.has_more) getComments();
      else if (more_answers) getAnswers();
      else process();
    }
  });  
}

getAnswers();

var SCORE_REG = /<h\d>\s*([^\n,]*[^\s,]),.*?(\d+)(?=[^\n\d<>]*(?:<(?:s>[^\n<>]*<\/s>|[^\n<>]+>)[^\n\d<>]*)*<\/h\d>)/;

var OVERRIDE_REG = /^Override\s*header:\s*/i;

function getAuthorName(a) {
  return a.owner.display_name;
}

function process() {
  var valid = [];
  
  answers.forEach(function(a) {
    var body = a.body;
    a.comments.forEach(function(c) {
      if(OVERRIDE_REG.test(c.body))
        body = '<h1>' + c.body.replace(OVERRIDE_REG, '') + '</h1>';
    });
    
    var match = body.match(SCORE_REG);
    if (match)
      valid.push({
        user: getAuthorName(a),
        size: +match[2],
        language: match[1],
        link: a.share_link,
      });
    
  });
  
  valid.sort(function (a, b) {
    var aB = a.size,
        bB = b.size;
    return aB - bB
  });

  var languages = {};
  var place = 1;
  var lastSize = null;
  var lastPlace = 1;
  valid.forEach(function (a) {
    if (a.size != lastSize)
      lastPlace = place;
    lastSize = a.size;
    ++place;
    
    var answer = jQuery("#answer-template").html();
    answer = answer.replace("{{PLACE}}", lastPlace + ".")
                   .replace("{{NAME}}", a.user)
                   .replace("{{LANGUAGE}}", a.language)
                   .replace("{{SIZE}}", a.size)
                   .replace("{{LINK}}", a.link);
    answer = jQuery(answer);
    jQuery("#answers").append(answer);

    var lang = a.language;
    if (/<a/.test(lang)) lang = jQuery(lang).text();
    
    languages[lang] = languages[lang] || {lang: a.language, user: a.user, size: a.size, link: a.link};
  });

  var langs = [];
  for (var lang in languages)
    if (languages.hasOwnProperty(lang))
      langs.push(languages[lang]);

  langs.sort(function (a, b) {
    if (a.lang > b.lang) return 1;
    if (a.lang < b.lang) return -1;
    return 0;
  });

  for (var i = 0; i < langs.length; ++i)
  {
    var language = jQuery("#language-template").html();
    var lang = langs[i];
    language = language.replace("{{LANGUAGE}}", lang.lang)
                       .replace("{{NAME}}", lang.user)
                       .replace("{{SIZE}}", lang.size)
                       .replace("{{LINK}}", lang.link);
    language = jQuery(language);
    jQuery("#languages").append(language);
  }

}
body { text-align: left !important}

#answer-list {
  padding: 10px;
  width: 290px;
  float: left;
}

#language-list {
  padding: 10px;
  width: 290px;
  float: left;
}

table thead {
  font-weight: bold;
}

table td {
  padding: 5px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link rel="stylesheet" type="text/css" href="//cdn.sstatic.net/codegolf/all.css?v=83c949450c8b">
<div id="answer-list">
  <h2>Leaderboard</h2>
  <table class="answer-list">
    <thead>
      <tr><td></td><td>Author</td><td>Language</td><td>Size</td></tr>
    </thead>
    <tbody id="answers">

    </tbody>
  </table>
</div>
<div id="language-list">
  <h2>Winners by Language</h2>
  <table class="language-list">
    <thead>
      <tr><td>Language</td><td>User</td><td>Score</td></tr>
    </thead>
    <tbody id="languages">

    </tbody>
  </table>
</div>
<table style="display: none">
  <tbody id="answer-template">
    <tr><td>{{PLACE}}</td><td>{{NAME}}</td><td>{{LANGUAGE}}</td><td>{{SIZE}}</td><td><a href="{{LINK}}">Link</a></td></tr>
  </tbody>
</table>
<table style="display: none">
  <tbody id="language-template">
    <tr><td>{{LANGUAGE}}</td><td>{{NAME}}</td><td>{{SIZE}}</td><td><a href="{{LINK}}">Link</a></td></tr>
  </tbody>
</table>

user68509

Posted 2017-04-25T12:46:04.770

Reputation:

Related – Leaky Nun – 2017-04-25T12:47:31.387

Welcome to PPCG! This looks like a nice challenge, BTW. – clismique – 2017-04-25T12:49:35.367

@Qwerp-Derp Thank you very much! I tried to be creative ^^ – None – 2017-04-25T12:51:06.870

@Zgarb Well it's exactly like the output of Leaky Nun. The sequence of the applications and then it shall end just before the beginning of the second cycle. I'll copy his output in the question so everyone can have a clear understanding. Thanks for pointing that out :) – None – 2017-04-25T13:09:19.880

@Antoine 1454 actually maps to 169. Should I just print the cycle or should I print everything from the start? – Leaky Nun – 2017-04-25T13:18:22.100

@LeakyNun You need to print everything that comes before the cycle and end the sequence with the cycle. Which is what you did because the next number would indeed be 169 – None – 2017-04-25T13:23:26.770

Related OEIS – mbomb007 – 2017-04-25T15:00:32.730

How important is the output formatting? Can we have the trailing comma, can the values be separated by a space or a newline instead? – 2501 – 2017-04-26T02:11:49.967

Hardcoding the value 169 is cheating? – 2501 – 2017-04-26T03:44:15.073

1@2501 Hardcoding the value is cheating, but concerning the output formatting you can use any separator you want – None – 2017-04-26T08:40:29.887

@Antoine Ok. The constant 169 doesn't help anyway, since some cycles don't contain it. – 2501 – 2017-04-26T08:46:08.100

Answers

19

Jelly, 6 bytes

D!SµÐĿ
    ÐĿ  Repeat until the results are no longer unique. Collects all intermediate results.
D           Convert from integer to decimal (list of digits)
 !          Factorial (each digit)
  S         Sum

Try it online!

I don't see any other way to make it shorter other than to do as told.

Specs

  • Input: 132 (as command-line argument)
  • Output: [132, 9, 362880, 81369, 403927, 367953, 368772, 51128, 40444, 97, 367920, 368649, 404670, 5810, 40442, 75, 5160, 842, 40346, 775, 10200, 6, 720, 5043, 151, 122, 5, 120, 4, 24, 26, 722, 5044, 169, 363601, 1454]

Leaky Nun

Posted 2017-04-25T12:46:04.770

Reputation: 45 011

I didn't expect to have an answer that short. Nice :) – None – 2017-04-25T12:55:08.833

4@Antoine It's Jelly :D It's always shorter than I think it'll be ;) – HyperNeutrino – 2017-04-25T12:56:05.923

8@HyperNeutrino Somehow Dennis will come with an even shorter answer – Leaky Nun – 2017-04-25T14:05:39.563

Somehow, yes. Because Dennis. :P – HyperNeutrino – 2017-04-25T14:18:16.667

So... Which character encoding do you use to come up with 6 bytes for those 6 characters? Isn't Jelly supposed to be UTF-8 encoded, meaning that this program is actually 9 bytes? – LordOfThePigs – 2017-04-26T11:03:24.990

@LordOfThePigs Jelly code page

– Leaky Nun – 2017-04-26T11:03:55.610

I see, thanks for educating me. I'm a noob at Code Golfing :-) – LordOfThePigs – 2017-04-26T11:10:45.250

10

Python 2, 88 bytes

import math
f=lambda x,l=[]:l*(x in l)or f(sum(math.factorial(int(i))for i in`x`),l+[x])

Try it online!

ovs

Posted 2017-04-25T12:46:04.770

Reputation: 21 408

As a python fan I'm glad someone answered with it, nice :) – None – 2017-04-25T13:53:45.947

9

05AB1E, 12 bytes

[DˆS!O©¯så#®

Try it online!

Explanation

[               # infinite loop
 Dˆ             # add a copy of current value to the global list (initialized as input)
   S            # split current number to digits
    !O          # calculate factorial of each and sum
      ©         # save a copy in register
       ¯så#     # if the current number is in the global list, exit loop
           ®    # retrieve the value from the register for the next iteration
                # implicitly output the global list

Emigna

Posted 2017-04-25T12:46:04.770

Reputation: 50 798

Short and correct, well played ! – None – 2017-04-25T13:54:53.640

Thought I could get rid of the s, was wrong, nice answer. – Magic Octopus Urn – 2017-04-25T16:18:44.450

8

Brachylog, 17 bytes

g:I{tẹḟᵐ+}ᵃ⁾L¬≠Lk

Try it online!

Explanation

g:I{     }ᵃ⁾         Accumulate I (a variable) times, with [Input] as initial input:
    t                  Take the last integer
     ẹḟᵐ+              Compute the sum of the factorial of its digits
            L        The result of the accumulation is L
            L­      Not all elements of L are different
               Lk    Output is L minus the last one (which is the start of the loop)

Fatalize

Posted 2017-04-25T12:46:04.770

Reputation: 32 976

What does I mean? – Leaky Nun – 2017-04-25T13:53:03.133

1@LeakyNun It's a parameter to ᵃ⁾. ᵃ³ means "accumulate 3 times". ᵃ⁾ means "accumulate as many times as the last element of the input", which in that case is I. Since I is a completely free variable, it will try values for it from 0 to +inf. – Fatalize – 2017-04-25T13:58:35.820

8

Wolfram Language, 62 60 56 bytes

Most@NestWhileList[Tr[IntegerDigits@#!]&,#,UnsameQ,All]&

It is really too bad that Wolfram Language has such abominably long function names. *Sigh*

Explanation:

Most[NestWhileList[Tr[IntegerDigits[#]!]&,#,UnsameQ,All]]&
                      IntegerDigits[#]                     (*Split input into list of digits*)
                                      !                    (*Factorial each element in the list*)
                   Tr[                 ]&                  (*Sum the list together*)
     NestWhileList[                      ,#,UnsameQ,All]   (*Iterate the function over itself, pushing each to a list, until a repeat is detected*)
Most[                                                   ]& (*Remove the last element in the list*)

Scott Milner

Posted 2017-04-25T12:46:04.770

Reputation: 1 806

Nice answer. I don't think this can be improved upon. – Kelly Lowder – 2017-04-25T21:52:12.240

1@KellyLowder Thanks! I was actually able to save two more bytes by mapping the factorial to the list, then summing it with Tr. – Scott Milner – 2017-04-25T22:10:20.230

1Nice use of NestWhileList[...,All]! – Greg Martin – 2017-04-26T00:45:21.233

6

JavaScript (ES6), 91 89 bytes

Saved 2 bytes thanks to fəˈnɛtɪk

It turns out to be quite similar to the other JS answer.

f=(n,x=!(a=[n]))=>n?f(n/10|0,x+(F=n=>n?n--*F(n):1)(n%10)):~a.indexOf(x)?a:f(x,!a.push(x))

f=(n,x=!(a=[n]))=>n?f(n/10|0,x+(F=n=>n?n--*F(n):1)(n%10)):~a.indexOf(x)?a:f(x,!a.push(x))

console.log(f(132))

Arnauld

Posted 2017-04-25T12:46:04.770

Reputation: 111 334

In your factorial function shouldn't you be able to use n instead of n>1 because 0!=1? – fəˈnɛtɪk – 2017-04-26T13:48:22.420

@fəˈnɛtɪk I don't know what I was thinking here. Thank you! – Arnauld – 2017-04-26T14:14:38.453

5

ClojureScript, 146 109 bytes

#(loop[n[%]](let[f(apply +(for[a(str(last n))](apply *(range 1(int a))))](if(some #{f}n)n(recur(conj n f)))))

Yikes, that is a monstrosity. Someone please help me golf this...

Thanks @cliffroot for shaving off a whopping 37 bytes!

This is an anonymous function, to run the function, you have to do this:

(#(...) {arguments})

TIO doesn't have ClojureScript, so here's a link to a ClojureScript REPL.

Here's a link to a Clojure program which prints the last element in the list from 0 to 1000.

Here's the output for 9999:

[9999 1451520 269 363602 1455 265 842 40346 775 10200 6 720 5043 151 122 5 120 4 24 26 722 5044 169 363601 1454]

I have a strong suspicion that all numbers must eventually settle at 1 or the loop [169 363601 1454].

Ungolfed code:

(defn fact-cycle [n]
  (loop [nums [n]]
    (let [fact-num
          (let [str-n (str (last nums))]
            (apply +
              (for [a (range (count str-n))]
                (apply *
                  (range 1
                    (inc (int (nth str-n a))))))))]
      (if (some #{fact-num} nums) nums
        (recur
          (conj nums fact-num))))))

Explanation coming soon!

clismique

Posted 2017-04-25T12:46:04.770

Reputation: 6 600

Quite long but correct ;) I cannot really help you to golf this sorry ^^ – None – 2017-04-25T13:54:35.607

the inner for can be (for[a s](apply *(range 1(-(int a)47)))), can't it? – cliffroot – 2017-04-25T14:39:57.890

and this will allow to get rid of the other let #(loop[n[%]](let[f(apply +(for[a(str(last n))](apply *(range 1(-(int a)47)))))](if(some #{f}n)n(recur(conj n f))))) – cliffroot – 2017-04-25T14:47:18.997

oh, seems you don't even need (- ... 47) in ClojureScript, just int will suffice – cliffroot – 2017-04-25T14:49:06.987

well, (inc(int a)) should do for ClojureScript and (-(int a)47) for Clojure. – cliffroot – 2017-04-25T14:59:41.067

(1), (2), (169, 363601, 1454), (363601, 1454, 169), (1454, 169, 363601), (871, 45361), (145), (45361, 871), (45362, 872), (872, 45362), (40585) are all cycles for n <= 10000000, so there are more than just [1] and [169 363601 1454] – ovs – 2017-04-26T14:04:09.023

5

Perl 6, 64 bytes

{my@a;$_,{[+] .comb.map:{[*] 2..$_}}...^{$_∈@a||!@a.push: $_}}

Try it

Expanded:

{

  my @a;             # array of values already seen

  $_,                # seed sequence with the input

  {
    [+]              # reduce using &infix:<+>
      .comb          # the digits of $_ (implicit method call)
      .map:          # do the following for each
      {
        [*] 2..$_    # get the factorial of
      }
  }


  ...^               # keep generating values until
                     # (「^」 means throw away the last value when done)

  {
      $_ ∈ @a        # is it an elem of @a? (「∈」 is shorter than 「(cont)」)

    ||               # if it's not

      !              # boolean invert so this returns False
        @a.push: $_  # add the tested value to @a
  }
}

Every line above that has { starts a new bare block lambda with an implicit parameter of $_.

I used [*] 2..$_ instead of [*] 1..$_ purely as a micro optimization.

Brad Gilbert b2gills

Posted 2017-04-25T12:46:04.770

Reputation: 12 713

4

JavaScript, 92 bytes

Thanks @Shaggy for golfing off one byte with includes
Thanks @Neil for golfing off two bytes

Code separated into individual functions 92 bytes

f=(x,a=[])=>a.includes(x)?a:f(k(x),a,a.push(x))
p=y=>y?y*p(y-1):1
k=n=>n?p(n%10)+k(n/10|0):0

Code on one line 92 bytes

f=(x,a=[])=>a.includes(x)?a:f((k=n=>n?(p=y=>y?y*p(y-1):1)(n%10)+k(n/10|0):0)(x),a,a.push(x))

Explanation

Initially call the function with just a single argument, therefore a=[].

If x exists in the array a return a a.includes(x)?a:...

Otherwise, append x to a and pass the factorial digit sum and a to the function (a.push(x),f(k(x),a))

p=y=>y?y*p(y-1):1
k=n=>n?p(n%10)+k(n/10|0):0

Factorial Digit sum performed so that it will not exceed the maximum recursion limit.

List of all possible endpoints: 1, 2, 145, 169, 871, 872, 1454, 40585, 45361, 45362, 363601

Try it online!

fəˈnɛtɪk

Posted 2017-04-25T12:46:04.770

Reputation: 4 166

1Gah, I was so close! Save a byte with f=(x,a=[])=>a.includes(x)?a:(a.push(x),f(k(x),a)) – Shaggy – 2017-04-25T14:25:32.287

Can you not write f(k(x),a,a.push(x))? Also, I think you can write k=n=>n&& to save another byte. – Neil – 2017-04-25T18:10:46.993

4

Haskell, 80 67 bytes

g#n|elem n g=g|h<-g++[n]=h#sum[product[1..read[d]]|d<-show n]
([]#)

Try it online! Usage: ([]#) 132

Edit: Saved 13 bytes with typs from Ørjan Johansen!

Laikoni

Posted 2017-04-25T12:46:04.770

Reputation: 23 676

(1) Test and append n instead of s(same as in ovs's Python answer), then f=([]#). (2) Switch the branches, inline s, and use elem. – Ørjan Johansen – 2017-04-25T17:40:37.513

Switch out your ++ for : also. – None – 2017-04-25T19:18:04.900

1@Canyon It's the wrong order around for that, it would give the final result reversed. You can almost fix it up afterwards, by prepending an extra n: and changing =g to =[], but it seems to be only a tie. – Ørjan Johansen – 2017-04-25T20:47:17.397

4

Pyth, 9 bytes

.us.!MjNT
.us.!MjNTQ  implicit Q

.u          explained below
       N      current value
      j T     convert to decimal (list of digits)
   .!M        factorial of each digit
  s           sum

Try it online!

This answer uses .u ("Cumulative fixed-point. Apply until a result that has occurred before is found. Return all intermediate results.")

Leaky Nun

Posted 2017-04-25T12:46:04.770

Reputation: 45 011

3

Pyth, 30 bytes

W!hxYQQ=+YQKQ=Q0WK=+Q.!%KT=/KT

Try It Here

Maria

Posted 2017-04-25T12:46:04.770

Reputation: 644

Pyth has more useful functions than one imagines. See my answer as reference.

– Leaky Nun – 2017-04-26T07:48:25.003

2

Python 3, 110 bytes

g=lambda x:x<1or x*g(x-1)
def f(n):
 a=[];b=n
 while b not in a:a+=[b];yield b;b=sum(g(int(x))for x in str(b))

Try it online!

Leaky Nun

Posted 2017-04-25T12:46:04.770

Reputation: 45 011

2

R, 120 Bytes

o=scan()
repeat {
q=sum(factorial(as.double(el(strsplit(as.character(o[length(o)]), "")))))
if(q%in%o)break
o=c(o,q)
}
o

Neil

Posted 2017-04-25T12:46:04.770

Reputation: 2 417

you can do o=scan(), use el() instead of [[1]], and gamma(n+1)=factorial(n) which I believe saves a byte, and I think as.numeric is the same as as.double for integers, which also saves a byte, and you can use toString instead of as.character. – Giuseppe – 2017-04-25T15:26:51.390

@Giuseppe Thanks for the input, updated. – Neil – 2017-04-25T16:07:11.643

2

Java 9 JSHell, 213 bytes

n->{Set<Integer>s=new HashSet<>();
return IntStream.iterate(n,i->(""+i).chars()
.map(x->x<50?1:IntStream.rangeClosed(2,x-48)
.reduce(1,(a,b)->a*b)).sum()).boxed()
.takeWhile(x->s.add(x)).collect(Collectors.toList());}

Try it online!

Note: This solution relies on the string representation of a number having code points in the range 48-57. Works for ASCII, UTF-8, Latin-1, all ISO-8859-* character sets, most code pages. Does not work for EBCDIC. I don't think anyone will deduct points for that. :)

Ungolfed:

Function<Integer, List<Integer>> f =        // function from Integer to List of Integer
n -> {
    Set<Integer> s = new HashSet<>();       // memo of values we've seen
    return IntStream.iterate(n,             // iterate over n, f(n), f(f(n)), etc.
    i -> (""+i).chars()                     // the sumFac function; for all chars
        .map(x -> x < 50? 1 :               // give 1 for 0! or 1!
        IntStream.rangeClosed(2, x-48)      // else produce range 2..d 
        .reduce(1,(a,b)->a*b))              // reduction to get the factorial
        .sum())                             // and sum up the factorii!

                                            // now we have a stream of ints
                                            // from applying sumFac repeatedly
        .boxed()                            // box them into Integers (thanks, Java)
        .takeWhile(x->s.add(x))             // and take them while not in the memo
        .collect(Collectors.toList());      // collect them into a list
}

Notes:

  • The return value of Set::add is very helpful here; returns true iff the item was not in the set
  • I was being sarcastic when I said "Thanks, Java"
  • factorii isn't really a word; I just made that up

David Conrad

Posted 2017-04-25T12:46:04.770

Reputation: 1 037

1I admit this is original ! Nice job :) – None – 2017-04-25T22:05:57.237

@Antoine I admit, Java isn't the best language to golf in, but it's hardly the craziest thing I've done lately. :) https://codegolf.stackexchange.com/a/117644/794

– David Conrad – 2017-04-25T22:18:16.400

2

Pyth, 22 11 bytes

.usm.!sd+Nk

Try it online!

Lots of credit to Leaky Nun's answer, which introduced me to .u, and helped save a massive 11 bytes of this program.

Explanation:

.usm.!sd+NkQ | ending Q is implicitly added
             | Implicit: Q = eval(input())
.u         Q | Repeat the function with initial value Q until a previous value is found. Return all intermediate values
  s          | Summation
   m.!sd     | For each character 'd' in the string, convert to integer and take the factorial
        +Nk  | Convert function argument to string

K Zhang

Posted 2017-04-25T12:46:04.770

Reputation: 5 698

Pyth has more useful functions than one imagines. See my answer as reference.

– Leaky Nun – 2017-04-26T07:48:21.643

@LeakyNun I've rewritten my answer to use .u. I guess I'll need to take a look through the character reference again to see if there are any other useful functions there. – K Zhang – 2017-04-27T00:11:07.540

You can use \Nto convert to string instead of+Nk`. – Leaky Nun – 2017-04-27T02:10:53.960

@LeakyNun Where the N would be obsolete then, and there comes a 9-byte solution... – Erik the Outgolfer – 2017-11-04T22:26:27.733

1

Axiom, 231 bytes

l(a:NNI):List NNI==(r:List NNI:=[];repeat(r:=cons(a rem 10,r);a:=a quo 10;a=0=>break);r)
g(a:NNI):NNI==reduce(+,[factorial(x) for x in l(a)])
h(a:NNI):List NNI==(r:=[a];repeat(a:=g(a);member?(a,r)=>break;r:=cons(a,r));reverse(r))

not golfed functions and some test

-- convert one NNI in its list of digits
listify(a:NNI):List NNI==
    r:List NNI:=[]
    repeat
        r:=cons(a rem 10,r)
        a:=     a quo 10
        a=0=>break
    r

-- g(1234)=1!+2!+3!+4!
SumfactorialDigits(a:NNI):NNI==reduce(+,[factorial(x) for x in listify(a)])

ListGenerateFromSumFactorialDigits(a:NNI):List NNI==
    r:=[a]
    repeat
       a:=SumfactorialDigits(a)
       member?(a,r)=>break
       r:=cons(a,r)
    reverse(r)

(9) -> h 132
   (9)
   [132, 9, 362880, 81369, 403927, 367953, 368772, 51128, 40444, 97, 367920,
    368649, 404670, 5810, 40442, 75, 5160, 842, 40346, 775, 10200, 6, 720,
    5043, 151, 122, 5, 120, 4, 24, 26, 722, 5044, 169, 363601, 1454]

RosLuP

Posted 2017-04-25T12:46:04.770

Reputation: 3 036

1

C, 161 bytes

f(a){return a?a*f(a-1):1;}
a(l){return l?f(l%10)+a(l/10):0;}
c,t,o;r(i){for(t=o=i;t=a(t),o=a(a(o)),c=t^o;);for(t=i;t^c;printf("%d ",t),c=c|t^o?c:o,t=a(t),o=a(o));}

See it work online.

2501

Posted 2017-04-25T12:46:04.770

Reputation: 748

1

TI-BASIC, 85 79 64 60 bytes

:Prompt L₁                             //Get input as 1 length list, 4 bytes
:Lbl C                                //create marker for looping, see below, 3 bytes
:int(10fPart(Xseq(10^(~A-1),A,0,log(X //split input into list of digits, 20 bytes
:sum(Ans!→X                           //factorial and sum the list, write to new input, 6 bytes
:If prod(L₁-X                         //Test to see if new element is repeated, see below, 7 bytes
:Then                                 //Part of If statement, 2 bytes
:augment(L₁,{X→L₁                     //Push new input to List 1, 10 bytes
:Goto C                               //Loop back to beginning, 3 bytes
:Else                                 //Part of If statement, 2 bytes
:L₁                                   //Print Answer, 2 bytes

Since this is running on a graphing calculator, there is limited RAM. Try testing it with numbers that loop quickly, like 169.

More Explanation:

:int(10fPart(Xseq(10^(~A-1),A,0,log(X
              seq(10^(~A-1),A,0,log(X //Get a list of powers of 10 for each digit (i.e. 1, 0.1, 0.01, etc.)
             X                        //Multiply by input
       fPart(                         //Remove everything but the decimal
     10                               //Multiply by 10 (move one digit in front of the decimal
:int(                                 //Truncate to an integer

If prod(L₁-X works by subtracting the new element from the old list, then multiplying all the elements of the list together. If the element was already in the list, the product will be 0, a falsey value. Otherwise, the product will be a positive integer, a truthy value.

Scott Milner

Posted 2017-04-25T12:46:04.770

Reputation: 1 806

1

Java 7, 220 bytes

String c(int n){String r=n+",",c;for(;!r.matches("^"+(c=(n=d(n))+",")+".*|.*,"+c+".*");r+=c);return r;}int d(int n){int s=0;for(String i:(n+"").split(""))s+=f(new Long(i));return s;}long f(long x){return x<2?1:x*f(x-1);}

Explanation:

String c(int n){                            // Method with integer parameter and String return-type
  String r=n+",",                           //  Result-String (which starts with the input integer + a comma
         c;                                 //  Temp String
  for(;!r.matches(                          //  Loop as long as the result-String doesn't match the following regex:
    "^"+(c=(n=d(n))+",")+".*|.*,"+c+".*");  //    "^i,.*|.*,i,.*" where `i` is the current integer
                                            //   `n=d(n)` calculates the next integer in line
                                            //   `c=(n=d(n))+","` sets the temp String to this integer + a comma
    r+=c                                    //   And append the result-String with this temp String
  );                                        //  End of loop
  return r;                                 //  Return the result-String
}                                           // End of method

int d(int n){                               // Separate method (1) with integer parameter and integer return-type
  int s=0;                                  //  Sum
  for(String i:(n+"").split(""))            //  Loop over the digits of `n`
    s+=f(new Long(i));                      //   And add the factorial of these digits to the sum
                                            //  End of loop (implicit / single-line body)
  return s;                                 //  Return the sum
}                                           // End of separate method (1)

long f(long x){                             // Separate method (2) with long parameter and long return-type (calculates the factorial)
                                            // (NOTE: 2x `long` and the `new Long(i)` is shorter than 2x `int` and `new Integer(i)`, hence long instead of int)
  return x<2?                               //  If `x` is 1:
      1                                     //   return 1
    :                                       //  Else:
      x*f(x-1);                             //   return `x` multiplied by the recursive-call of `x-1`
}                                           // End of method (2)

Test code:

Try it here.

class M{
  String c(int n){String r=n+",",c;for(;!r.matches("^"+(c=(n=d(n))+",")+".*|.*,"+c+".*");r+=c);return r;}int d(int n){int s=0;for(String i:(n+"").split(""))s+=f(new Long(i));return s;}long f(long x){return x<2?1:x*f(x-1);}

  public static void main(String[] a){
    System.out.println(new M().c(132));
  }
}

Output:

132,9,362880,81369,403927,367953,368772,51128,40444,97,367920,368649,404670,5810,40442,75,5160,842,40346,775,10200,6,720,5043,151,122,5,120,4,24,26,722,5044,169,363601,1454,

Kevin Cruijssen

Posted 2017-04-25T12:46:04.770

Reputation: 67 575

1

GolfScript, 44 bytes

~]{..)\;10base{,1\{)*}/}%{+}*.@\+@@?)!}do);`

~                                             eval input
 ]                                            initialization
  {                                   }do     do...
   ..)\;                                          initialization
        10base                                    get digits
              {,1\{)*}/}%                         factorial each
                         {+}*                     sum
                             .@\+@@?)!        while result not found
                                         );   drop last element
                                           `  tostring

Try it online!

The factorial part is from here.

Leaky Nun

Posted 2017-04-25T12:46:04.770

Reputation: 45 011

1

J, 40 31 bytes

Edit: 9 bytes saved using the improvements by FrownyFrog. Thanks!

f=.$:@,~`]@.e.~[:+/@:!10#.inv{:

Original code:

f=.[`($:@,)@.([:-.e.~)[:+/!@("."0&":@{:)

In this case I decided to count the bytes for the verb definition, since otherwise it doesn't work in the interpreter.

Explanation:

                         (        {:) - Takes the last element of the array
                               ":@    - converts it to string
                          "."0&       - converts each character back to integer
                       !@             - finds the factorials
                     +/               - sums them
                   [:                 - cap (there are 2 derived verbs above, we need 3 for a fork)
          (    e.~)                   - check if the result is present in the list    
             -.                       - negates the above check
           [:                         - cap
        @.                            - Agenda conjunction, needed for the recursion
  ($:@,)                              - if the result is not in the list, add it to the list and recur
[`                                    - if the result is in the list, display it and stop    

Try it online!

Galen Ivanov

Posted 2017-04-25T12:46:04.770

Reputation: 13 815

1([:-.e.~) -> (1-e.~) – FrownyFrog – 2017-11-04T17:34:07.097

131 bytes – FrownyFrog – 2017-11-04T18:13:20.583

@FrownyFrog Thanks, your code is much better! I tried 10#.inv early while experimenting, but then I wrote it 10&#.inv and it was longer, so I rejected it. Thanks for all your suggestions! I have much to learn :) – Galen Ivanov – 2017-11-04T18:46:25.250

@FrownyFrog Reversing the cases for the agenda is so good, I regret I didn't see it :) – Galen Ivanov – 2017-11-04T18:53:20.160

[:+/!@"."0@":@{: is the same length, so there's no improvement with 10#.inv. Just had to drop the (). – FrownyFrog – 2017-11-04T18:54:54.200

Yes, I just saw it - its not ambiguous to require () – Galen Ivanov – 2017-11-04T19:02:12.453

1

Husk, 6 bytes

U¡oṁΠd

Try it online!

Erik the Outgolfer

Posted 2017-04-25T12:46:04.770

Reputation: 38 134

1

Tcl, 143 bytes

proc P {n L\ ""} {proc F n {expr $n?($n)*\[F $n-1]:1}
while {[set n [expr [join [lmap d [split $n ""] {F $d}] +]]] ni $L} {lappend L $n}
set L}

Try it online!

sergiol

Posted 2017-04-25T12:46:04.770

Reputation: 3 055