Calcola la somma delle differenze delle cifre di un numero


39

Prendi in considerazione di prendere un numero intero non negativo come 8675309 e calcolare i valori assoluti delle differenze tra tutte le coppie di cifre vicine.

Per 8675309otteniamo |8-6| = 2, |6-7| = 1, |7-5| = 2, |5-3| = 2, |3-0| = 3, |0-9| = 9. Stringing questi risultati insieme produce un altro, più piccolo numero intero non negativo: 212239. Ripetendo il processo si ottiene 11016, quindi 0115, che per convenzione che gli zeri iniziali non vengono scritti semplifica come 115, che diventa 04o 4, che non può essere ulteriormente ridotto. Sommando tutti questi valori otteniamo 8675309 + 212239 + 11016 + 115 + 4 = 8898683.

Definiamo la somma delle differenze delle cifre (o DDS) come questa operazione di prendere ripetutamente le differenze delle cifre di un numero per formare un nuovo numero, quindi aggiungere tutti i numeri risultanti all'originale.

Ecco i primi 20 valori nella corrispondente sequenza DDS:

N   DDS(N)
0   0
1   1
2   2
3   3
4   4
5   5
6   6
7   7
8   8
9   9
10  11
11  11
12  13
13  15
14  17
15  19
16  21
17  23
18  25
19  27

Ecco i primi 10000 valori , il cui grafico è abbastanza curioso:

Trama DDS 10000

Soprattutto dal momento che sembra lo stesso quando lo si stampa su 1000 o anche su 100:

Trama DDS 1000

Trama DDS 100

(Lo definirei la scala del dentista ...)

Sfida

Scrivi un programma o una funzione che accetta un numero intero non negativo e stampa o restituisce il suo valore DDS. Ad esempio, se l'input fosse 8675309, l'output dovrebbe essere 8898683.

Vince il codice più breve in byte.


scala del dentista?
Martijn,

12
@MartijnR Scala del dentista.
Calvin's Hobbies,

@ Scala dell'ortodontista di Calvin'sHobbies?
Decadimento beta

1
@BetaDecay Scala del dentista .
Alex A.,

Risposte:


11

Pyth, 17

s.ui.aM-VJjNTtJTQ

Provalo qui o esegui Test Suite

Spiegazione:

s.u            Q   # Cumulative reduce, i.e. getting the intermediate values of each reduce
                     step and returning them as a list, then sum the list
   i ... T         # Convert the resulting list of numbers into a base 10 number
   .aM             # Get the absolute value of each element of ...
      -VJjNTtJ     # Perform vector subtraction on the lists given by
        JjNT       # assign J the number we currently have converted to its base 10 digits
            tJ     # and J[1:]. e.x. for 123 we get J = [1,2,3] then we do
                   # zip(J,J[1:]) which gives [[1,2],[2,3]] then element wise subtract
                   # to get [-1, -1]

Che lingua è questa? Così criptico! T_T
as

1
@asgs Benvenuto in PPCG :) Si chiama Pyth, puoi trovare un interprete e alcuni documenti nella sua pagina Github . La maggior parte degli utenti di questa lingua è attiva su questo sito, quindi se hai domande a riguardo ti
invitiamo

17

Python 2, 73

Fortunatamente, sono riuscito a evitare qualsiasi operazione di stringa.

t=lambda n:n>9and abs(n%10-n/10%10)+10*t(n/10)
g=lambda n:n and n+g(t(n))

g è la funzione che calcola la risposta.


4
Cos'è questa magia nera ?!
Decadimento beta

7
@BetaDecay Credo che si chiami "matematica".
lirtosiast,

Non conosco Python abbastanza bene da dirlo, ma puoi applicare l'operazione rimanente ad entrambi i termini in un colpo solo? Cioè, (n-n/10)%10funzionerebbe come n%10-n/10%10? O forse anche (9*n/10)%10?
Glen O,

@GlenO In Python, %è un vero operatore di modulo, non un resto, quindi non funzionerebbe.
feersum,

15

Matlab, 101 105 byte

Grazie mille a @beaker per il suo suggerimento di utilizzare polyvalinvece se base2dec. Questo mi ha permesso di farlo

  • salva 4 byte;
  • semplifica notevolmente la generalizzazione su base arbitraria (vedi sotto) e salva lì 22 byte; e soprattutto,
  • mi ha aiutato a capire che il codice per il caso generale era sbagliato (gli zeri iniziali non venivano rimossi). Il codice e i grafici sono corretti ora.

Codice:

function y=f(y)
x=+num2str(y);while numel(x)>1
x=polyval(abs(diff(x)),10);y=y+x;x=+dec2base(x,10);end

Esempio:

>> f(8675309)
ans =
     8898683

Bonus: base arbitraria

Una piccola generalizzazione consente di utilizzare una base numerica arbitraria, non necessariamente decimale:

  • Base arbitraria da 2 a 10, 108 104 byte

    function y=f(y,b)
    x=+dec2base(y,b);while numel(x)>1
    x=polyval(abs(diff(x)),b);y=y+x;x=+dec2base(x,b);end
    

    Il motivo per cui questo funziona solo per la base fino a 10è che di Matlab dec2baseutilizza la funzione cifre 0, 1, ..., 9, A, B, ..., e c'è un salto di caratteri (ASCII) i codici da 9a A.

  • Base arbitraria da 2 a 36, 124 146 byte

    Il salto da 9a Asopra menzionato richiede un trattamento speciale. La base massima è 36secondo la dec2basefunzione di Matlab .

    function y=f(y,b)
    x=+dec2base(y,b);x(x>57)=x(x>57)-7;while numel(x)>1
    x=abs(diff(x));x=x(find(x,1):end);y=y+polyval(x,b);end
    

Ecco come le scale del dentista cercano diverse basi:

inserisci qui la descrizione dell'immagine inserisci qui la descrizione dell'immagine inserisci qui la descrizione dell'immagine inserisci qui la descrizione dell'immagine inserisci qui la descrizione dell'immagine inserisci qui la descrizione dell'immagine


1
Questo è quello che avrei fatto ... tempo di pensare a un'altra risposta lol. +1.
rayryeng - Ripristina Monica il

@rayryeng :-) Grazie
Luis Mendo,

@BetaDecay Grazie! :-) Sono davvero piuttosto
Luis Mendo il

11

CJam, 22 21 byte

ri_{\s2ew::-:zsi_@+}h

Si noti che questo programma esce con un errore, che è consentito per impostazione predefinita .

Con l'interprete Java, gli errori possono essere eliminati chiudendo STDERR. Se provi questo codice online nell'interprete CJam , ignora tutto l'output prima dell'ultima riga.

Grazie a @ Sp3000 per aver segnalato un errore nella revisione originale.

Grazie a @ MartinBüttner per il golf off 1 byte.

Esempio di esecuzione

$ cjam digit-difference.cjam 2>&- <<< 8675309     
8898683

Come funziona

ri_   e# Read an integer (I) from STDIN and push a copy (A).
{     e# Do:
  \   e#   Swap I on top of A.
  s   e#   Cast I to string.
      e#   For example, 123 -> "123".
  2ew e#   Push the overlapping slices of length 2 (pair of adjacent digits).
  ::- e#   Replace each pair by its difference.
  :z  e#   Apply absolute value to each difference.
  si  e#   Cast to string, then to integer. This is the new I.
      e#   For example, [1 2 3] -> "123" -> 123.
  _   e#   Push a copy of I.
  @   e#   Rotate A on top of the copy of I.
  +   e#   Add I to A, updating A.
}h    e# While A is truthy, repeat the loop.

A sarà sempre veritiero quando controllato da h. Tuttavia, una volta che I è un numero intero a una cifra, 2ewfallirà con un errore dopo aver consumato l'array su cui è stato chiamato. Questo lascia solo il risultato desiderato sulla pila, che viene stampata prima di uscire.


2
Pubblicato in 7 minuti piatti: O
Calvin's Hobbies,

10

Labyrinth , 176 134 127 119 103 97 88 82 79 76 72 byte

Grazie a Sp3000 per aver salvato 1 byte e spianato la strada per altri 2.

Questo potrebbe probabilmente essere ancora abbreviato, ma ehi, batte Java Matlab Python ...

?
_
)/:}+{:`};!
9       "
_ :}-"" :_10
;;{: `" "  :
  {  (_:/=%}
  0+;`"

Provalo online.

Questo termina con un errore ma il messaggio di errore viene scritto su STDERR (motivo per cui non lo vedi in TIO).

L'implementazione è abbastanza semplice. Aggiungiamo il valore corrente a un totale parziale. Se il valore corrente era maggiore di 9, calcoliamo le sue cifre di base 10 (tramite ripetute div-mod) e formiamo un nuovo numero dalle differenze assolute. Se arriviamo a 9o meno, stampiamo il totale parziale.

Le cifre del numero corrente vengono raccolte nello stack ausiliario con la cifra più significativa in cima.

Bene, l'implementazione di fantasia abs(...)che avevo qui si è rivelata ridicolmente complicata rispetto alla nuova soluzione ... Aggiungerò una spiegazione aggiornata quando avrò finito di giocare a golf.


5

Java - 300 byte

Versione golfizzata

static Long t=new Scanner(System.in).nextLong();static char[]c=t.toString().toCharArray();public static void main(String[]z){while(c.length>1)s();System.out.print(t);}static void s(){String s="";for(int i=0;i<c.length-1;)s+=Math.abs(c[i]-c[++i]);Long a=new Long(s);t+=a;c=a.toString().toCharArray();}

Versione Ungolfed / Full

import java.util.Scanner;

public class DigitDifference {

    static Long t = new Scanner(System.in).nextLong();
    static char[] c = t.toString().toCharArray();

    public static void main(String[] args){
        while( c.length > 1 )
            s();
        System.out.print(t);
    }

    static void s(){
        String s="";
        for(int i = 0; i < c.length-1;)
            s += Math.abs(c[i]-c[++i]);
        Long a = new Long(s);
        t += a;
        c = a.toString().toCharArray();
    }
}

@Loovjo, Saluti ..
The Coder,

1
Benvenuti in PPCG! Questo può ancora essere giocato molto. Non ho esaminato molto la logica ma: 1) Metti tutto questo in una funzione poiché non ti serve davvero una separata (o un programma / classe completo per quella materia) 2) Sbarazzati delle statics dopo aver tirato li in 3) (a+"")è generalmente lo stesso a.toString(), ma più corto 4) Non è necessario uno scanner se è solo una funzione, basta impiegare molto tempo come input.
Geobits,

2
Ad esempio, senza cambiare gran parte del lavoro e solo rimuovendo l'innesto, sono circa 164:long f(long t){long a=t;char[]c;while((c=(a+"").toCharArray()).length>1){String s="";for(int i=0;i<c.length-1;)s+=Math.abs(c[i]-c[++i]);t+=a=new Long(s);}return t;}
Geobits

2
@Geobits, è stato un amico fantastico. Sono nuovo di Code Golf, quindi cercherò di migliorare la mia efficienza di codign. Cherrs ..
The Coder,

5

Julia, 81 60 byte

n->(s=n;while n>9 s+=n=int(join(abs(diff(["$n"...]))))end;s)

Ungolfed:

function f(n::Int)
    # Initialize a sum to the input
    s = n

    while n > 9
        # Get absolute values of the pairwise differences of the
        # digits of n, join as a string, convert it to an integer,
        # and reassign n
        n = int(join(abs(diff(["$n"...]))))

        # ["$n"...] actually splits n as a string into a vector
        # of its characters, but the difference between ASCII
        # codes is the same as the difference between the numbers
        # so it works as expected

        # Add the new n to the running sum
        s += n
    end

    # Return the sum
    return s
end

Provalo online

Risparmiato 21 byte grazie a feersum e Glen O!


1
C'è qualche motivo ndigits(n)>1è diverso da n>9?
feersum,

Suggerimento: int(join(abs(diff(["$n"...]))))salva 9 byte. Passare a n>9come suggerito da feersum per altri 9 byte salvati. Salva altri tre byte eseguendo entrambi i compiti nel ciclo while in un solo passaggio (e rimuovendo il punto e virgola extra, ora non necessario):n->(s=n;while n>9 s+=n=int(join(abs(diff(["$n"...]))))end;s)
Glen O

@feersum Um, no. Grazie!
Alex A.

@GlenO Fantastico, grazie!
Alex A.

5

OK , 37 32 24 23 byte

+/(10/{%x*x}1_-':.:'$)\

In azione:

  +/(10/{%x*x}1_-':.:'$)\8675309
8898683

  (+/(10/{%x*x}1_-':.:'$)\)'!20
0 1 2 3 4 5 6 7 8 9 11 11 13 15 17 19 21 23 25 27

K5 ha alcune caratteristiche che ben si adattano a questo: "codifica" e "decodifica" possono eseguire la conversione di base, ogni coppia ( ':) accoppia elementi sequenziali in un elenco e la scansione a punto fisso ( \) può produrre la sequenza iterata fino al suo arresto mutevole. La mancanza di una primitiva abs()porta a qualche sgradevole massa sotto forma di {(x;-x)x<0}', però.

Modificare:

Invece {(x;-x)x<0}', posso (un po 'sprecare) prendere la radice quadrata del quadrato della sequenza ( {%x*x}risparmiando 5 byte.

Modifica 2:

Ispirato dalla soluzione APL di @maurinus, posso sostituire il "decodifica" ( ((#$x)#10)\x) con la valutazione di ogni carattere della rappresentazione in stringa del numero- .:'$x! Questo mi permette anche di usare una forma tacita dell'intera espressione, salvando caratteri aggiuntivi.


4

Python 2, 87 byte

f=lambda n:n and n+f(int('0'+''.join(`abs(int(a)-int(b))`for a,b in zip(`n`,`n`[1:]))))

Aggiunge ricorsivamente il numero corrente e rileva le differenze tra le cifre. Un sacco di conversione tra numeri e stringhe. Probabilmente può essere migliorato.


4

Julia, 55 48 byte

h=n->(n>9&&h(int(join(abs(diff(["$n"...]))))))+n

Ungolfed:

function h(n)
  if n>9
    # If multiple digits, find the digit difference...
    digitdiff=int(join(abs(diff(["$n"...]))))
    # ... recurse the function...
    downsum=h(digitdiff)
    # ... and return the sum so far (working up from the bottom)
    return downsum+n
  else
    # If single digit, no further recursion, return the current number
    return n
  end
end

In sostanza, questo ricade fino al livello di una cifra (dove non è possibile eseguire alcuna differenza di cifra), quindi esegue il riepilogo quando esce dalla ricorsione, livello per livello.


3

Haskell, 140 byte

d fa il lavoro.

import Data.Char
d n=sum.m(read.m intToDigit).fst.span(/=[]).iterate s.m digitToInt.show$n
s l@(h:t)=snd$span(==0)$m abs$zipWith(-)l t
m=map

Qualcuno sa come evitare di importare le funzioni di conversione lunghe?


intToDigitè toEnum.(+48)ed digitToIntè (\i->fromEnum i-48). È anche possibile attivare sa una versione pointfree con =<<in contesto di lista: s=snd.span(==0).m abs.(zipWith(-)=<<tail). Infine, (==0)è (<1)perché stiamo lavorando con numeri interi non negativi.
nimi,

... oh, e se sè inutile, non c'è bisogno di dargli un nome. Chiamalo direttamente:iterate(snd.span ... tail))
nimi,

... sono di nuovo io a correggere un errore nel mio primo commento: =<<viene utilizzato nel contesto della funzione, non nel contesto dell'elenco, scusate.
nimi,

Brillante! Inoltre, è una procedura comune qui utilizzare le estensioni GHC? NoMonomorphismRestrictionmi dfarà avere anche inutili.
Leif Willerts,

1
chre ordsono entrambi dentro Data.Char, quindi non puoi omettere il file import. Anche i flag del compilatore vengono conteggiati come byte, quindi NoMonomorphismRestrictionaumenta il tuo punteggio di 25.
nimi


3

APL (22)

{⍵≤9:⍵⋄⍵+∇10⊥|2-/⍎¨⍕⍵}

Spiegazione:

  • ⍵≤9:⍵: se ⍵ ≤ 9, restituisce ⍵ invariato.
  • ⍎¨⍕⍵: converti ⍵ in una stringa, quindi valuta ogni carattere
  • 2-/: sottrarre ogni due numeri adiacenti
  • |: accetta i valori assoluti
  • 10⊥: trasforma l'array in un numero di base 10
  • ⍵+∇: chiama la funzione in modo ricorsivo con questo nuovo valore e aggiungi il risultato all'input

3

Mathematica, 72 69 65 byte

Tr@FixedPointList[FromDigits@*Abs@*Differences@*IntegerDigits,#]&

Sono aperto ai suggerimenti qui.


Tr@FixedPointList[FromDigits@*Abs@*Differences@*IntegerDigits,#]&
alephalpha

@alephalpha Concetto interessante, creando zero in più ...
LegionMammal978

2

JavaScript ES6, 73 byte

t=n=>(b=10,M=Math).ceil(n&&n+t((j=n=>n>9&&M.abs(n%b-n/b%b)+b*j(n/b))(n)))

Questo non sta diventando più breve: / Proverò più approcci ma questo è il più breve finora


Se lo lasci solo come una funzione anonima invece di assegnarlo a tè ancora valido e ti fa risparmiare 2 byte.
Patrick Roberts,

@PatrickRoberts sì, ma sto usando la ricorsione, quindi devo nominarlo
Downgoat,

Oh, l'ho mancato, abbastanza giusto.
Patrick Roberts,

2

JavaScript (ES6), 69

Prova a eseguire lo snippet di seguito in un browser compatibile con EcmaScript 6 (ma non Chrome in quanto non supporta ancora l'operatore di diffusione ...) MS Edge forse?

f=n=>n&&(n+=r='',[...n].map(d=>(r+=d>p?d-p:p-d,p=d),p=n[0]),+n+f(+r))

function test()
{
  var i=+I.value
  O.innerHTML = i+' -> '+f(i) + '\n' + O.innerHTML 
}
<input id=I value=8675309><button onclick=test()>-></button>
<pre id=O></pre>

Alternativa, usando la comprensione dell'array che ora è indirizzata a EcmaScript 2016 (ES7), 67 byte:

f=n=>n&&(n+=r='',p=n[0],[for(d of n)(r+=d>p?d-p:p-d,p=d)],+n+f(+r))

2

Python 3, 125 byte

Mi piaceva la mancanza di regex finché non ho provato a usarlo per questa sfida ... nonre.findall('\d\d',s,overlapped=True) è attivo ;)

s=input()
p=int
x=p(s)
while p(s)>9:g=str(s);s=p(''.join(str(abs(p(g[i])-p(g[i+1])))for i in range(len(g)-1)));x+=s 
print(x)

Saluti @Todd :)


1
È possibile eseguire l'aggiunta sul posto su un numero intero anziché su un elenco che rimuoverà la necessità di parentesi quadre e la somma finale. 's = p (input ())' ti permetterà di rimuovere la conversione int sul ciclo while e l'assegnazione a x. Prendi anche in considerazione il ciclo attraverso la zip di ge [1:] che dovrebbe salvare alcuni byte.
Todd,

1

J, 70 byte

 +/([:10&#.[:(2|@:-/\])[:10&(]#:~[#~[:>.[^.])])`]@.(11&>)^:a:".(1!:1)3

0

C 162 byte

golfed:

main(int argc,char **argv){char *c=argv[1];int u=atoi(c),d;do{while(c[1]!=0){*c=abs(*c-*(c+1))+48;c++;}*c=0;c=argv[1];d=atoi(c);u+=d;}while(d>9);printf("%d",u);}

ungolfed:

main(int argc, char **argv)
{
    char *c=argv[1];
    int u=atoi(c),d;

    do
    {
        while(c[1]!=0)
        {
            *c=abs(*c-*(c+1))+48;
            c++;
        }

        *c=0;
        c=argv[1];
        d=atoi(c);
        u+=d;
    }
    while(d>9);

    printf("%d\n",u);
}

0

R, 134 byte

Codice

f=function(x){z=x;while(z>9){n=seq(nchar(z));z=abs(diff(strtoi(substring(z,n,n))));z=sum(z*10**(rev(seq(length(z)))-1));x=x+z};cat(k)}

Provalo online .

Ungolfed

f=function(x){
  z=x;
  while(z>9){
    n=seq(nchar(z));
    z=abs(diff(strtoi(substring(z,n,n))));
    z=sum(z*10**(rev(seq(length(z)))-1));
    x=x+z
  };
  cat(x)
}

Ecco il grafico della differenza della serie "Somma della differenza di cifre di un numero" da f (1) a f (1m). Solo perché amo diff.

Codice di trama

s <- seq(1,100000)
serie <- sapply(s,f)
plot(diff(ts(serie)),xlab="",ylab="")

0

MATLAB (141)(137)

EDIT: 4 byte in meno, grazie a @Andras

function[s j]=n(T,b,c),if(T/b>9),u=fix(T/10);[x e]=n(T,b*10,0);y=n(u,b,0);[w z]=n(u,b,c);s=abs(x-y);j=s+e+10*c*z;else,s=mod(T,10);j=s;end
  • Questo ha battuto la risposta di @LuisMendo, ma almeno avrei potuto ridurre i tempi di esecuzione, che avrei cercato di diversificare i modi per affrontare questo problema.
  • Potrei ridurlo di più, ma andando avanti per meno tempo, spreco più byte, quindi ecco il principio:

Il programma sta sommando le cifre della stessa riga prima delle cifre incorporate, significa che ha usato solo la divisione intera "n / 10" log_10 (n) volte, la complessità è O (N).

Se n= a b c d

a          b           c           d
   |a-b|       |b-c|       |c-d|
    ||a-b|-|b-c|| ||b-c|-|c-d||
   ....

Il mio programma calcola:

a+|a-b| + | |a-b|-|b-c| |  +  |  | |a-b|-|b-c| | - | |b-c|-|c-d| |  |
+10*(
b+|b-c| + | |b-c|-|c-d| |
+10*(
c+|c-d|
+10*(
d
)
)
)

Uso:

  [a b]=n(13652,1,1)

a =

1

 b =

   16098

È possibile risparmiare 4 byte omettendo il facoltativo ,enddella functiondichiarazione.
Andras Deak,

Per favore, considera di rivedere la grammatica del tuo post. Non riesco proprio a capire cosa hai detto.
rayryeng - Ripristina Monica il

0

Prolog, 143 byte

Codice:

q(X,N):-X<9,N=0;A is abs(X mod 10-X//10 mod 10),Y is X//10,q(Y,M),N is A+M*10.
r(X,N):-X<9,N=X;q(X,Y),r(Y,M),N is X+M.
p(X):-r(X,N),write(N).

Ha spiegato:

q(X,N):-X<9,N=0;                                                         % If only one digit, the difference is 0
        A is abs(X mod 10-X//10 mod 10),Y is X//10,q(Y,M),N is A+M*10.   % Else, the difference is the difference between the last 2 digits + the recursive difference of the number without the last digit
r(X,N):-X<9,N=X;                                                         % If we only have 1 digit the final answer is that digit
        q(X,Y),r(Y,M),N is X+M.                                          % Else, the final answer is the current number + the recursive difference of that number
p(X):-r(X,N),write(N).         

q esegue i calcoli che convertono un numero in Differenza cifra.
r chiama ricorsivamente qe riassume i risultati per trovare la somma delle differenze delle cifre.
p è il punto di ingresso. Prende un numero, chiama re stampa la risposta.

Esempio:

>p(8675309).
8898683

Provalo online qui .


0

PHP - 198 byte

<?$x=$t=$_GET['V'];function z($x){global$t;for($i=0;$i<strlen($x)-1;$i++){$z=str_split($x);$r.=str_replace('-','',$z[$i]-$z[$i+1]);}$r=ltrim($r,'0');$t+=$r;return strlen($r)>1?z($r):0;}z($x);echo$t;

Ungolfed

<?
$x=$t=$_GET['V']; // Gets the value from input
function z($x){
    global$t;
    for($i=0;$i<strlen($x)-1;$i++){
        $z=str_split($x); //Turns the string into an array
        $r.=str_replace('-','',$z[$i]-$z[$i+1]); // Sums the two values and removes the minus signal
    }
    $r=ltrim($r,'0'); // Remove trailing zeroes
    $t+=$r; // Adds to global var
    return strlen($r)>1?z($r):0; // Checks the size of the string. If >1, calls the function again
}

z($x);
echo$t;

0

Perl 6 , 56 byte

{[+] $_,{+.comb.rotor(2=>-1)».map((*-*).abs).join}…0} # 56 bytes

utilizzo:

my &code = {...} # insert code from above

(180..190).map: &code;
# (259 258 259 260 261 262 263 264 265 266 280)

say code 8675309; # 8898683
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.