Se stai solo cercando di contare quante volte viene ridotto e non ti preoccupi specificamente della ricorsione ... puoi semplicemente rimuovere la ricorsione. Il codice seguente rimane fedele alla Posta originale in quanto non viene considerato num <= 9
come necessitante riduzione. Pertanto, singleDigit(8)
avranno count = 0
e singleDigit(39)
avranno count = 3
, proprio come stanno dimostrando l'OP e la risposta accettata:
const singleDigit = (num) => {
let count = 0, ret, x;
while (num > 9) {
ret = 1;
while (num > 9) {
x = num % 10;
num = (num - x) / 10;
ret *= x;
}
num *= ret;
count++;
console.log(num);
}
console.log("Answer = " + num + ", count = " + count);
return num;
}
Non è necessario elaborare i numeri 9 o meno (ad es. num <= 9
). Sfortunatamente il codice OP elaborerà num <= 9
anche se non lo conta. Il codice sopra non elaborerà né conta num <= 9
affatto. Lo passa solo attraverso.
Ho scelto di non usare .reduce
perché eseguire la matematica effettiva era molto più veloce da eseguire. E, per me, più facile da capire.
Ulteriore riflessione sulla velocità
Sento che anche il buon codice è veloce. Se stai usando questo tipo di riduzione (che è molto usato in numerologia) potrebbe essere necessario utilizzarlo su una grande quantità di dati. In questo caso, la velocità diventerà la massima importanza.
L'uso di entrambi .map(Number)
e console.log
(ad ogni passo della riduzione) è molto lungo da eseguire e non necessario. La semplice cancellazione .map(Number)
dall'OP lo ha accelerato di circa 4,38x. Eliminazioneconsole.log
accelerato così tanto che era quasi impossibile testarlo correttamente (non volevo aspettarlo).
Quindi, simile alla risposta del committente personalizzato , non usare .map(Number)
né trasferireconsole.log
i risultati in un array e usare .length
for count
è molto più veloce. Sfortunatamente per la risposta del committente personalizzato , l'utilizzo di una funzione del generatore è davvero molto lento (tale risposta è circa 2,68 volte più lenta dell'OP senza .map(Number)
econsole.log
)
Inoltre, invece di usare .reduce
ho appena usato la matematica attuale. Solo questa singola modifica ha velocizzato la mia versione della funzione di un fattore di 3,59x.
Infine, la ricorsione è più lenta, occupa spazio nello stack, utilizza più memoria e ha un limite a quante volte può "ripetersi". Oppure, in questo caso, quanti passaggi di riduzione può utilizzare per completare la riduzione completa. Distribuire la tua ricorsione in loop iterativi mantiene tutto nello stesso posto nello stack e non ha limiti teorici su quanti passi di riduzione può usare per finire. Pertanto, queste funzioni qui possono "ridurre" quasi qualsiasi numero intero di dimensioni, limitato solo dal tempo di esecuzione e dalla lunghezza di un array.
Tutto questo in mente ...
const singleDigit2 = (num) => {
let red, x, arr = [];
do {
red = 1;
while (num > 9) {
x = num % 10;
num = (num - x) / 10;
red *= x;
}
num *= red;
arr.push(num);
} while (num > 9);
return arr;
}
let ans = singleDigit2(39);
console.log("singleDigit2(39) = [" + ans + "], count = " + ans.length );
// Output: singleDigit2(39) = [27,14,4], count = 3
La funzione sopra è estremamente veloce. È circa 3,13 volte più veloce dell'OP (senza .map(Number)
e console.log
) e circa 8,4 volte più veloce della risposta del committente personalizzato . Tenere presente che l'eliminazione console.log
dall'OP impedisce che produca un numero in ogni fase della riduzione. Quindi, la necessità qui di inserire questi risultati in un array.
PT
.map(Number)
è ridondante poiché l'*
operatore obbliga comunque i valori a numerare. ;-)