16
\$\begingroup\$

The persistence of a number \$x = d_1d_2d_3...d_n\$, with \$d_1 \ne 0\$, under some function \$f : \mathbb N_0 \times \mathbb N_0 \to \mathbb N_0\$ is defined as the number of applications of \$f\$ to the digits of \$x\$ before it reaches a single digit integer. That is, if we have the map

$$I_f: (x = d_1d_2d_3...d_n) \mapsto f(f(...f(d_1, d_2), d_3), ...), d_n),$$

the persistence is defined as

$$P_f(x) = \begin{cases} 0, & x \in \{0,1,2,3,4,5,6,7,8,9\} \\ 1 + P_f(I_f(x)), & \text{otherwise} \end{cases}$$

Some examples include:

  • Additive persistence: \$P_+(2718) = 2\$, \$P_+(5) = 0\$ and \$P_+(2677889) = 3\$
  • Multiplicative persistence: \$P_\times(68889) = 7\$, \$P_\times(25) = 2\$ and \$P_\times(8) = 0\$
  • Minimal/maximal digit: \$P_{\min}(1734) = 1\$, \$P_{\max}(48203) = 1\$ and \$P_{\min}(5) = 0\$

Given a blackbox function \$f : \mathbb N_0 \times \mathbb N_0 \to \mathbb N_0\$ and a positive integer \$x = d_1d_2d_3...d_n\$, where \$d_i\$ are digits with \$d_1 \ne 0\$, output the persistence of \$x\$ under \$f\$.

You may assume that \$f\$ will eventually reach a single digit number when repeatedly applied to \$x\$'s digits.

This is a challenge, so shortest code wins.

Test cases

f(x, y), x -> output
x + y, 2677889 -> 3
x × y, 68889 -> 7
x ** y, 29 -> 4
φ(x × y), 736 -> 2                 (φ is the Euler Totient function)
x/2 + (x × y), 1234567 -> 5        (using floor division)
|x - y|, 9 -> 0
\$\endgroup\$
3

14 Answers 14

7
\$\begingroup\$

K (ngn/k), 14 bytes

{#1_(x/.'$:)\}

Try it online!

Uses .'$: instead of 10\ because the latter gives () for 0 (and */ of () is 1), breaking the (*, 68889) test case.

{#1_(x/.'$:)\}    Curried function, 1st arg: f, 2nd arg: n
    (      )\     repeat and collect starting from n until convergence:
       .'$:         digits
     x/             reduce by x
 #1_              length minus 1
\$\endgroup\$
6
\$\begingroup\$

Python, 70 71 bytes

p=lambda f,n:n>9and-~p(f,(i:=lambda n:f(i(n//10),n%10)if n>9else n)(n))

Attempt This Online!

Takes in an anonymous function f and an integer n.


+1 bytes from @xnor for noticing an error when n=0 in i.

Python, 65 bytes

p=lambda f,n:~-len(n)and-~p(f,reduce(f,n))
from functools import*

Attempt This Online!

Takes in an anonymous function f and a string n representing an integer.

Python 2, 42 bytes

p=lambda f,n:~-len(n)and-~p(f,reduce(f,n))

Attempt This Online!

Same as above. Posted based on the recommendation of @tsh.

\$\endgroup\$
3
  • 1
    \$\begingroup\$ You can remove the from functools import* by switching to Python 2. \$\endgroup\$
    – tsh
    Sep 5 at 2:24
  • 1
    \$\begingroup\$ Man, I thought you were some new user I'd never seen before, but then I spelled out the character codes and it matched the pfp lol \$\endgroup\$
    – Steffan
    Sep 5 at 3:23
  • 1
    \$\begingroup\$ It looks like the and/or in your first solution catches a hitch when getting n=0: TIO. You can fall back to an if/else for +1 byte; maybe you see better. \$\endgroup\$
    – xnor
    Sep 5 at 21:14
4
\$\begingroup\$

Vyxal, 6 bytes

£‡¥RİL

Try it Online!

Takes inputs from the stack due to technical limits.

£      # Store function to register
 ‡--   # Next two elements as a function...
   R   # Reduce by (implicit digits)...
  ¥    # The function stored in the register
    İ  # Apply that function until the result doesn't change, not including the initial value
     L # Count the number of different values.
\$\endgroup\$
3
  • \$\begingroup\$ Try it Online! for 5 bytes by setting the input in the header. I think it should be valid \$\endgroup\$
    – lyxal
    Sep 5 at 0:41
  • \$\begingroup\$ @lyxal I'd say it isn't really, since it's not something you can do normally. \$\endgroup\$
    – emanresu A
    Sep 5 at 0:45
  • \$\begingroup\$ It's the equivalent of putting a function into the inputs though. It's setting STDIN. I'll ask in chat \$\endgroup\$
    – lyxal
    Sep 5 at 0:46
4
\$\begingroup\$

PARI/GP, 38 bytes

g->p(n)=if(n>9,1+p(fold(g,digits(n))))

Attempt This Online!

A curried function that takes input as (f)(x).

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

Jelly, 7 bytes

Dç/$ƬL’

Try it online!

Takes a function from the previous line and a number from an argument.

Dç/$       Convert an integer to its decimal digits and reduce by the input function
    Ƭ      Repeat and collect the results until the results are not unique
           (repeats after reaching a single digit number)
     L’    Get its length minus 1
\$\endgroup\$
3
\$\begingroup\$

05AB1E, 12 10 bytes

ΔÅ»X.V}θ}N

Assumes the function is defined as a string in variable X.

Try it online or verify all test cases.

Explanation:

Δ       # Apply until the result no longer changes,
        # using the (implicit) input-integer in the first iteration:
 Å»     #  Reduce the digits of the integer by, keeping all intermediate results:
   X    #   Push function-string `X`
    .V  #   Evaluate and execute it as 05AB1E code
  }θ    #  After the reduce-by: only keep the resulting last value
}N      # After the until-no-more-changes-loop: push the last 0-based index of the loop
        # (which is output implicitly as result)

Unfortunately, 05AB1E lacks functions, so we'll have to store the 'black box function' in a string and execute it as 05AB1E code with .V.
In addition, 05AB1E's regular reduce-by builtin only works with single builtins (e.g. .»*), so we'll have to use the reduce-by that keeps intermediate results and then just keep the final result, in order to have a larger body with multiple builtins (pushing X, and executing as 05AB1E .V in this case). (e.g. Å»*}θ).

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

Haskell, 47 44 bytes

f#n=sum[1+f#foldl1 f[read[x]|x<-show n]|n>9]

Try it online!

  • saved 3 Bytes thanks to @xnor

# is an infix function taking the function to apply as f and a integer number as n.

Uses the trick shorter conditionals when one outcome is the empty list combined with a recursive approach by @xnor idea.

If n > 9 yeld 1+ result of # with number transformed, the result is the sum.

\$\endgroup\$
1
  • \$\begingroup\$ 44 bytes \$\endgroup\$
    – xnor
    Sep 5 at 21:04
2
\$\begingroup\$

Japt, 11 bytes

Black-box function is pre-assigned to variable V, although functions that consist of a single basic operation can be passed via input variable V.

@=ìrV)¨A}fÄ

Try it

\$\endgroup\$
2
+300
\$\begingroup\$

Prolog (SWI), 90 bytes

X/Y/Z:-Y<10,Z=0;number_codes(Y,A),maplist(plus(48),[F|B],A),foldl(X,B,F,S),X/S/H,Z is H+1.

Try it online!

90 bytes by Steffan.

\$\endgroup\$
2
  • \$\begingroup\$ You can use , instead of ->. It will provide multiple choicepoints, but that's fine: Try it online! \$\endgroup\$
    – Steffan
    Sep 7 at 16:15
  • \$\begingroup\$ 90 bytes using operators instead of functions: Try it online! \$\endgroup\$
    – Steffan
    Sep 7 at 16:16
1
\$\begingroup\$

Ruby, 47 bytes

->g,n{n>9?1+f[g,n.digits.reverse.reduce(&g)]:0}

Try it online!

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

JavaScript (ES6), 48 bytes

Expects (F)(n), where n is passed as a string. Returns false for 0.

F=>g=n=>n>9&&g([...n].map(x=>+x).reduce(F)+'')+1

Try it online!

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

Burlesque, 19 bytes

{XXr[}j1ia1jC~qlnfi

Try it online!

{XX    # As digits
 r[    # Reduce by F
}j1ia  # Insert F before reduce
1jC~   # Evaluate infinitely
qlnfi  # Find first single digit index
\$\endgroup\$
1
\$\begingroup\$

BQN, 25 bytes

{𝕩>9?1+𝕊𝔽˜´⌽'0'-˜•Fmt𝕩;0}

Defines a 1-modifier that can be applied to a dyadic function F, turning it into a monadic function that takes a single number and returns its persistence under F. Try it at BQN online!

Explanation

Here 𝔽 is the original dyadic function, 𝕊 is the modified function, and 𝕩 is the single argument of the modified function.

{𝕩>9?1+𝕊𝔽˜´⌽'0'-˜•Fmt𝕩;0}
{                        }  Block (which is a 1-modifier due to the presence of 𝔽 in it)
 𝕩>9                         Does the argument have multiple digits?
    ?                        If so (recursive case):
                  •Fmt𝕩       Format the argument as a string
             '0'-˜            Subtract '0' from each char, giving a list of digits
           ⌽                  Reverse
          ´                   Right fold on:
        𝔽˜                    𝔽 with reversed arguments
       𝕊                      Recurse on that value
     1+                       Add one to the result of the recursive call
                       ;0    Otherwise (base case), return 0

Unfortunately, BQN doesn't have a left-fold modifier. Scan works left-to-right, but then it costs two bytes to extract the last value from the result list.

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

tinylisp, 66 bytes

(load library
(d P(q((F N)(i(l N 10)0(a 1(P F(foldl F(to-base 10 N

Defines a function P that takes a function F and a number N and returns the persistence of N under F. Try it online!

Explanation

(load library

The library contains definitions for foldl and to-base.

(d P(q((F N)

Define P to be a function of two arguments, F and N.

(i(l N 10)0

If N is less than 10, return 0. Otherwise...

(a 1(P F

Add 1 to the result of calling P recursively on F and the result of...

(foldl F(to-base 10 N

Convert N to its base-10 digits and left-fold on F.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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