2009-12-16 13 views
6

Praticamente quello che dice il titolo. Ho una lista di Interi in questo modo: [1,2,3]. Voglio cambiare questo in Integer 123. Il mio primo pensiero è stato concat ma non funziona perché è del tipo sbagliato, ho provato varie cose ma di solito finisco per restituire la stessa lista. Qualsiasi aiuto molto apprezzato.Converti un elenco di numeri interi in un Int (come concat) in haskell

Anche I hanno trovato un modo per stampare la cosa giusta (putStr) tranne che voglio che il tipo sia Integer e putStr non lo fa.

risposta

21

È possibile utilizzare foldl di combinare tutti gli elementi di una lista:

fromDigits = foldl addDigit 0 
    where addDigit num d = 10*num + d 

La funzione addDigit viene chiamata da foldl per aggiungere le cifre, uno dopo l'altro, a partire da quello più a sinistra.

*Main> fromDigits [1,2,3] 
123 

Edit:
foldl passeggiate attraverso la lista da sinistra a destra, aggiungendo gli elementi di accumulare un certo valore.

Il secondo argomento di foldl, 0 in questo caso, è il valore iniziale del processo. Nel primo passaggio, tale valore iniziale viene combinato con 1, il primo elemento dell'elenco, chiamando addDigit 0 1. Questo risulta in 10 * 0 + 1 = 1. Nel passaggio successivo questo 1 è combinato con il secondo elemento della lista, per , dando 10 * 1 + 2 = 12. Quindi questo è combinato con il terzo elemento della lista , da addDigit 12 3, risultante in 10 * 12 + 3 = 123.

Quindi moltiplicare inutilmente per zero è solo il primo passo, nei passaggi seguenti la moltiplicazione è effettivamente necessaria per aggiungere le nuove cifre "alla fine" del numero accumulato.

+7

Or way cooler point free - fromDigits = foldl ((+). (* 10)) 0 :) –

+0

Fantastico! Funziona perfettamente. Questo era quello che pensavo di dover fare ma l'hai fatto molto più bello di quanto avrei potuto grazie! – Paul

+0

Quindi funziona, ma non sono esattamente sicuro di come funzioni la parte addDigit. So che foldl prende una funzione e una lista lo fa su tutti gli elementi della lista .. ma addDigit sembra moltiplicare 0 (num) per 10 e quindi aggiungere l'elemento .. che aggiungerebbe solo l'elemento .. quindi cosa sono Mi manca? – Paul

9

Si potrebbe concat le rappresentazioni di stringa dei numeri, e poi li read indietro, in questo modo:

joiner :: [Integer] -> Integer 
joiner = read . concatMap show 
+2

Questo trasforma '[12,34]' in '1234' - diversamente da sth, che lo trasforma in' 154', o in quello di Chris, che commette errori. Il comportamento desiderato dell'OP non è stato specificato abbastanza. – ephemient

+0

sth funziona perché utilizzo sempre numeri a 1 cifra. Questo è anche il modo in cui mi piacerebbe che funzioni ... ma qualcuno potrebbe spiegare esattamente come funziona l'addDigit in sth? – Paul

2

Usa read e anche intToDigit:

joinInt :: [Int] -> Int 
joinInt l = read $ map intToDigit l 

ha il vantaggio (o svantaggio) di vomitare su numeri a più cifre.

0

Per quanto riguarda come stampare il numero, invece di

putStr n 

Basta provare

putStr (show n) 

Il ragionamento è che putStr può solo stringhe di stampa. Quindi è necessario convertire il numero in una stringa prima di inviarlo.

Si potrebbe anche voler provare la funzione print da Preludio. Questo può stampare tutto ciò che è "visualizzabile" (qualsiasi istanza della classe Show), non solo le stringhe. Ma sappiate che print n corrisponde (approssimativamente) a putStrLn (show n), non a putStr (show n).

+0

A proposito, questa dovrebbe essere davvero una domanda a parte ... –

1

Un'altra idea sarebbe quella di dire: l'ultima cifra conta per 1, il penultimo numero per 10, la cifra prima per 100, eccetera. Quindi per convertire un elenco di cifre in un numero, è necessario invertirlo (per iniziare sul retro), moltiplicare le cifre insieme ai corrispondenti poteri di dieci e aggiungere il risultato insieme.

Per invertire un elenco, utilizzare reverse, per ottenere le potenze di dieci è possibile utilizzare iterate (*10) 1 (provarlo in GHCi o Abbracci!), Per moltiplicare le cifre corrispondenti di due liste utilizzare zipWith (*) e aggiungere tutto insieme, utilizzare sum - aiuta davvero a conoscere alcune funzioni della libreria! Mettendo insieme i pezzi, si ottiene

fromDigits xs = sum (zipWith (*) (reverse xs) (iterate (*10) 1)) 

Esempio di valutazione:

fromDigits [1,2,3,4] 
    ==> sum (zipWith (*) (reverse [1,2,3,4]) [1,10,100,1000, ....] 
    ==> sum (zipWith (*) [4,3,2,1] [1,10,100,1000, ....]) 
    ==> sum [4 * 1, 3 * 10, 2 * 100, 1 * 1000] 
    ==> 4 + 30 + 200 + 1000 
    ==> 1234 

Tuttavia, questa soluzione è più lento di quelli con foldl, a causa della chiamata al reverse e dal momento che si sta costruendo quei poteri di dieci solo per usarli di nuovo direttamente. Tra l'altro, questo modo di costruire numeri è più vicino al modo in cui la gente di solito pensa (almeno io!), Mentre le -solutions in sostanza usano Horner's rule.

+0

La lista è sintassi valida in GHC? Tutto quello che ho qui è Abbracci, e sicuramente non funziona lì. – Chuck

+0

No, questa lista serve solo a spiegare quale (parte) ha il risultato di 'iterate (* 10) 1'. Neanche in GHC. – yatima2975

-2

Non sono esperto in Haskell, ma questo è il modo più semplice che riesco a pensare per una soluzione a questo problema che non implichi l'utilizzo di altre funzioni esterne.

ConcatDigits :: [Int] -> Int 
ConcatDigits [] = 0 
ConcatDigits xs = ConcatReversed (ReverseDigits xs) 1 

ReverseDigits :: [Int] -> [Int] 
ReverseDigits [] = [] 
ReverseDigits (x:xs) = (ReverseDigits xs) : x 

ConcatReversed :: [Int] -> Int -> Int 
ConcatReversed [] d = 0 
ConcatReversed (x:xs) d = (x*d) + ConcatReversed xs (d*10) 

Come potete vedere, ho pensato che stiate provando a concatenare una lista di cifre. Se per caso non è questo il tuo caso, sono abbastanza sicuro che questo non funzionerà. :(

Nella mia soluzione, prima di tutto ho definito una funzione chiamata ReverseDigits, che inverte l'elenco originale. Per esempio [1,2,3] a [3,2,1]

Dopo che, io uso una funzione ConcatReversed che prende un elenco di cifre e il numero d, che è il risultato di dieci potere la prima cifra nella posizione di lista.Se la lista è vuota restituisce 0, e in caso contrario, restituisce la prima cifra sui tempi lista d, più la chiamata al ConcatReversed passare il resto della lista e d volte dieci.

Speranza il codice parlano da sé, perché penso che il mio povero spiegazione inglese non è stato molto utile.

+0

-1: le funzioni non di costruzione sono in minuscolo. IMO anche non molto intuitivo. –

+0

Credo che questa sia una risposta perfettamente valida. Ero chiaro che non sono un esperto di Haskell, quindi non uccidermi se non conosco le convenzioni di codifica. – Fede

Problemi correlati