Фактори та цикли, що не закінчуються!


33

Як ви знаєте, факториал додатного цілого числа nє добутком усіх натуральних чисел, рівних або меншим n.

Наприклад :

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

Тепер ми визначимо спеціальну операцію з невідповідною назвою, наприклад sumFac:

З огляду на додатне ціле число n, sumFac(n)це сума факторіалів цифр.

Наприклад :

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

Завдання

Ваша місія, незалежно від того, чи приймете ви це чи ні, полягає в тому, щоб повернути послідовність (потенційно нескінченну) додатків sumFacдо цілого числа, заданого вхідними даними.

Приклад: 132 -> 132, 9, 362880, 81369, 403927, ...

Але це ще не все! Дійсно, програми з sumFacчасом створять цикл. Ви також повинні повернути цей цикл!

Якщо у вашій мові є вбудований фактор, ви можете використовувати її. Я не вибагливий щодо типу повернення, ви просто повинні повернути послідовність додатків sumFac та цикл у форматі, зрозумілому людині.

EDIT: Щоб допомогти вам візуалізувати, як повинен виглядати вихід, я скопіював Leaky Nun трохи нижче:

[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]

Вам просто потрібно зупинити послідовність, коли цикл ось-ось розпочнеться вдруге!

Але це код-гольф, тому найкоротша відповідь у байтах виграє!

Таблиця лідерів

Ось фрагмент стека для створення як звичайного табло, так і огляду переможців за мовою.



Ласкаво просимо до PPCG! Це виглядає як приємний виклик, BTW.
клісмік

@ Qwerp-Derp Дуже дякую! Я намагався бути творчим ^^

@ Zgarb Ну, це точно як вихід Leaky Nun. Послідовність заявок, а потім вона закінчується безпосередньо перед початком другого циклу. Я скопію його висновок у запитання, щоб кожен мав чітке розуміння. Дякуємо, що

1
@ 2501 Значення жорсткого кодування - це обман, але стосовно форматування виводу ви можете використовувати будь-який потрібний роздільник

Відповіді:


19

Желе , 6 байт

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

Спробуйте в Інтернеті!

Я не бачу іншого способу скоротити його, окрім як сказано.

Технічні характеристики

  • Введення: 132(як аргумент командного рядка)
  • Вихід: [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]

Я не очікував, що відповідь буде такий короткий. Ніцца :)

4
@Antoine Це желе: D Це завжди коротше, ніж я думаю, що буде;)
HyperNeutrino

8
@HyperNeutrino Як-то Денніс прийде з ще коротшою відповіддю
Leaky Nun

Якось так. Тому що Денніс. : P
HyperNeutrino

Отже ... Яке кодування символів ви використовуєте, щоб створити 6 байт для цих 6 символів? Чи не належить Jelly бути кодованим UTF-8, це означає, що ця програма насправді становить 9 байт?
LordOfThePigs


9

05AB1E , 12 байт

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

Спробуйте в Інтернеті!

Пояснення

[               # 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

Короткий і правильний, добре зіграний!

Думав, що я можу позбутися s, помилився, приємна відповідь.
Magic Octopus Urn

8

Брахілог , 17 байт

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

Спробуйте в Інтернеті!

Пояснення

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)

Що Iозначає?
Leaky Nun

1
@LeakyNun Це параметр для ᵃ⁾. ᵃ³означає «накопичувати 3 рази». ᵃ⁾означає "накопичити стільки разів, скільки останній елемент вводу", який у такому випадку є I. Оскільки Iце абсолютно вільна змінна, вона спробує значення для неї від 0до +inf.
Фаталізувати

8

Мова Вольфрама, 62 60 56 байт

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

Дійсно дуже погано, що мова Wolfram має такі гидотно довгі назви функцій. * Зітхання *

Пояснення:

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*)

Гарна відповідь. Я не думаю, що це можна покращити.
Келлі Лоудер

1
@KellyLowder Дякую! Мені вдалося зберегти ще два байти, зіставивши факторіал до списку, а потім підсумувавши його Tr.
Скотт Мілнер

1
Приємного використання NestWhileList[...,All]!
Грег Мартін

6

JavaScript (ES6), 91 89 байт

Збережено 2 байти завдяки fəˈnɛtɪk

Це виявляється досить схожим на іншу відповідь JS .

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))


У вашій факторіальній функції ви не повинні використовувати n замість n> 1, тому що 0! = 1?
fəˈnɛtɪk

@ fəˈnɛtɪk Я не знаю, що я тут думав. Дякую!
Арнольд

5

ClojureScript, 146 109 байт

#(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, це жахливість. Хтось, будь ласка, допоможіть мені гольф у цьому ...

Спасибі @cliffroot за те, що голили колосальні 37 байт!

Це анонімна функція, щоб запустити функцію, ви повинні це зробити:

(#(...) {arguments})

У TIO немає ClojureScript, тому ось посилання на ClojureScript REPL.

Ось посилання на програму Clojure, яка друкує останній елемент у списку від 0 до 1000.

Ось результат для 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]

У мене є сильні підозри, що всі числа повинні врешті-решт осісти в 1циклі або в циклі[169 363601 1454] .

Невикористаний код:

(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))))))

Пояснення найближчим часом!


Досить довго, але правильно;) Я не можу допомогти вам

внутрішнє forможе бути (for[a s](apply *(range 1(-(int a)47)))), чи не може?
Скеля

і це дозволить позбутися іншого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)))))
скелі

о, здається, вам навіть не потрібно (- ... 47)в ClojureScript, просто intвистачить
cliffroot

ну, (inc(int a))слід робити для ClojureScript і (-(int a)47)для Clojure.
Скеля

5

Perl 6 , 64 байти

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

Спробуй це

Розширено:

{

  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
  }
}

Кожен рядок вище, що має, {починає новий головий блок лямбда з неявним параметром $_.

Я використовував [*] 2..$_замість [*] 1..$_чисто як мікрооптимізацію.


4

JavaScript, 92 байти

Спасибі @Shaggy за те, що ти граєш на один байт, включає в себе
подяку @Neil за те, що ти займаєш два байти

Код розділений на окремі функції 92 байти

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

Код в одному рядку 92 байти

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))

Пояснення

Спочатку викликайте функцію лише одним аргументом, тому a = [].

Якщо в масиві існує х, повернення a a.includes(x)?a:...

В іншому випадку додайте х до а і передайте функції факторної цифри та а функції (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

Факторна сума цифр виконується так, щоб вона не перевищувала максимальну межу рекурсії.

Список усіх можливих кінцевих точок: 1, 2, 145, 169, 871, 872, 1454, 40585, 45361, 45362, 363601

Спробуйте в Інтернеті!


1
Гах, я був так близько! Збережіть байт за допомогоюf=(x,a=[])=>a.includes(x)?a:(a.push(x),f(k(x),a))
Shaggy

Ти не можеш писати f(k(x),a,a.push(x))? Крім того, я думаю, ви можете написати, k=n=>n&&щоб зберегти ще один байт.
Ніл

4

Haskell , 80 67 байт

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

Спробуйте в Інтернеті!Використання:([]#) 132

Редагувати: Збережено 13 байт друкарськами Ørjan Johansen!


(1) Тестуйте та додайте nзамість s(те саме, що у відповіді Pyshon ovs) f=([]#). (2) Перемикайте гілки, вбудовуйте sта використовуйте elem.
Ørjan Johansen

Перемкніть ваш ++FOR :також.

1
@Canyon Це неправильний порядок навколо цього, це дало б зворотний результат. Ви можете майже виправити це потім, на випереджаючи додаткову n:і зміни =gв =[], але це , здається, тільки краватку.
Ørjan Johansen

4

Pyth, 9 байт

.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

Спробуйте в Інтернеті!

Ця відповідь використовує .u("Сукупна фіксована точка. Застосовуйте, поки результат не відбувся раніше. Поверніть усі проміжні результати.")




2

R, 120 байт

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

ви можете зробити o=scan(), використовувати el()замість [[1]], і gamma(n+1)=factorial(n)який я вважаю , зберігає байти, і я думаю , що as.numericце так само , як as.doubleдля цілих чисел, які також економлять байти, і ви можете використовувати toStringзамість as.character.
Джузеппе

@Giuseppe Дякую за вклад, оновлено.
Ніл

2

Java 9 JSHell, 213 байт

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());}

Спробуйте в Інтернеті!

Примітка. Це рішення покладається на рядкове представлення числа, що має кодові точки в діапазоні 48-57. Працює для ASCII, UTF-8, Latin-1, усіх наборів символів ISO-8859- *, більшості кодових сторінок. Не працює для EBCDIC. Я не думаю, що за це ніхто не нарахує бали. :)

Безголівки:

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
}

Примітки:

  • Тут дуже допомагає повернене значення Set :: add; повертає правду iff елемент не був у наборі
  • Я був саркастичним, коли сказав "Спасибі, Ява"
  • factorii насправді не є словом; Я щойно це придумав

1
Зізнаюся, це оригінально! Приємна робота :)

@Antoine Зізнаюся, Java - не найкраща мова для гольфу, але навряд чи це найбожевільне, що я робив останнім часом. :) codegolf.stackexchange.com/a/117644/794
Девід Конрад

2

Pyth, 22 11 байт

.usm.!sd+Nk

Спробуйте в Інтернеті!

Багато кредиту на відповідь Лікі Нун , яка мене познайомила .uі допомогла зберегти величезні 11 байт цієї програми.

Пояснення:

.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

У Pyth більше корисних функцій, ніж у однієї уяви. Дивіться мою відповідь як посилання.
Leaky Nun

@LeakyNun Я переписав свою відповідь на використання .u. Напевно, мені потрібно ще раз переглянути посилання на символи, щоб побачити, чи є ще якісь корисні функції.
K Чжан

Ви можете використовувати `Nдля перетворення в рядок замість +Nk.
Лина монашка

@LeakyNun Куди Nб тоді було застаріло, і з'являється 9-байтове рішення ...
Ерік Вигнавець

1

Аксіома, 231 байт

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))

не гольф функції та деякий тест

-- 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]

1

Java 7, 220 байт

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);}

Пояснення:

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)

Код тесту:

Спробуйте тут.

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));
  }
}

Вихід:

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,



1

TI-BASIC, 85 79 64 60 байт

: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

Оскільки це працює на графічному калькуляторі, оперативна пам'ять обмежена. Спробуйте протестувати його з числами, які швидко циклічно, наприклад 169.

Більше пояснення:

: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працює, віднімаючи новий елемент зі старого списку, потім множуючи всі елементи списку разом. Якщо елемент вже був у списку, продукт матиме 0значення фальси. В іншому випадку добуток матиме додатне ціле ціле число.



1

J , 40 31 байт

Редагувати: 9 байтів збережено за допомогою поліпшень FrownyFrog. Спасибі!

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

Оригінальний код:

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

У цьому випадку я вирішив порахувати байти для визначення дієслова, оскільки в іншому випадку це не працює в інтерпретаторі.

Пояснення:

                         ({:) - Бере останній елемент масиву
                               ": @ - перетворює його в рядок
                          "." 0 & - перетворює кожен символ назад у ціле число
                       ! @ - знаходить фабрики
                     + / - підсумовує їх
                   [: - cap (є два похідних дієслова вгорі, нам потрібно 3 для виделки)
          (е. ~) - перевірте, чи є результат у списку    
             -. - заперечує вищевказану перевірку
           [: - шапка
        @. - Зв'язок порядку денного, необхідний для рекурсії
  ($: @,) - якщо результату немає у списку, додайте його до списку та повторіть
[`- якщо результат є у списку, виведіть його та зупиніть    

Спробуйте в Інтернеті!


1
([:-.e.~)->(1-e.~)
FrownyFrog


@FrownyFrog Спасибі, ваш код набагато краще! Я спробував 10 # .inv рано під час експерименту, але потім написав це 10 & # inv і це було довше, тому я відхилив його. Дякуємо за всі ваші пропозиції! У мене є чому навчитися :)
Гален Іванов

@FrownyFrog Повернення справ до порядку денного настільки добре, я шкодую, що не бачив його :)
Гален Іванов

[:+/!@"."0@":@{:однакової довжини, тому покращення з цим немає 10#.inv. Просто довелося скинути ().
FrownyFrog

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.