2015-04-28 12 views
6

Sto cercando un metodo piacevole per dividere un numero con n cifre in Clojure ho questi due metodi verbose inefficienti:Come dividere un numero in Clojure?

(->> (str 942) 
     seq 
     (map str) 
     (map read-string)) => (9 4 2) 

e ...

(defn digits [n] ;YUK!! 
    (cons 
     (str (mod n 10)) (lazy-seq (positive-numbers (quot n 10))))) 

(map read-string (reverse (take 5 (digits 10012)))) => (1 0 0 1 2) 

C'è un altro metodo conciso per fare questo tipo di operazione?

+0

Il tuo grado di semplificare il vostro primo metodo per '(- >> 942 str (mappa (comp lettura-string str)))'. – Thumbnail

+0

Davvero! grazie mille;) – adebesin

+0

L'ho aggiunto e un'abbreviazione corrispondente del tuo secondo metodo, a [la mia risposta] (http://stackoverflow.com/a/29942388/1562315). – Thumbnail

risposta

5

Una versione di gestire il primo metodo è

(defn digits [n] 
    (->> n str (map (comp read-string str)))) 

... e del vostro secondo è

(defn digits [n] 
    (if (pos? n) 
    (conj (digits (quot n 10)) (mod n 10)) 
    [])) 

Un idiomatica alternativa

(defn digits [n] 
    (->> n 
     (iterate #(quot % 10)) 
     (take-while pos?) 
     (mapv #(mod % 10)) 
     rseq)) 

Per esempio,

(map digits [0 942 -3]) 
;(nil (9 4 2) nil) 
  • Il calcolo è essenzialmente ansioso, poiché l'ultima cifre in è il primofuori. Quindi potremmo anche usare mapv e rseq (anziché map e reverse) per farlo più velocemente.
  • La funzione è pronta per il trasduttore.
  • Funziona correttamente solo con numeri positivi.
5

Si potrebbe semplicemente fare

(map #(Character/digit % 10) (str 942))

EDIT: Aggiunta di una definizione di funzione

(defn digits [number] (map #(Character/digit % 10) (str number))) 

Usage:

(digits 1234) 

Nota: Questa è conciso, ma fa uso di Java String e classi di personaggi. Un'implementazione efficiente può essere scritta utilizzando l'intero modulo aritmetico, ma non sarà concisa. Una tale soluzione simile alla risposta di Charles' sarebbe:

(defn numTodigits 
    [num] 
    (loop [n num res []] 
    (if (zero? n) 
     res 
     (recur (quot n 10) (cons (mod n 10) res))))) 

Source

5

io non sono sicuro di concisa, ma questo evita inefficienza inutili come la conversione di stringhe e di nuovo a numeri interi.

(defn digits [n] 
    (loop [result (list), n n] 
    (if (pos? n) 
     (recur (conj result (rem n 10)) 
      (quot n 10)) 
     result))) 
0

Un'implementazione ricorsiva (potrebbe essere più efficiente e meno concisa, ma non dovrebbe essere importante per numeri ragionevoli).

(defn digits [n] 
    (when (pos? n) 
    (concat (digits (quot n 10)) 
      [(mod n 10)]))) 
+1

Qui bisogna fare attenzione a esaurire lo stack quando si elaborano numeri molto grandi. –

+1

Creare un vettore di un singolo oggetto solo per 'concat' non è una buona idea. Poiché il risultato di '(mod n 10)' è sempre un numero singolo, 'conj' o' cons' sarebbero scelte migliori. – muhuk

+0

@mujuk 'cons' o' conj' farebbe la lista inversa. @Charles sono d'accordo, stavo solo cercando di scrivere qualcosa di conciso. Se il requisito avesse dichiarato che gli input potrebbero avere migliaia di cifre, non avrei usato la ricorsione pura. –

0

un metodo loop:

(defn split-numbers [number] 
    (loop [itr 0 res [] n number] 
    (if (= n 0) 
     res 
     (recur (inc itr) (concat (vector (mod n 10)) res) (int (/ n 10))) 
     ) 
    ) 
    ) 
Problemi correlati