2009-12-16 8 views
6

Más o menos lo que dice el título. Tengo una lista de enteros como esta: [1,2,3]. Quiero cambiar esto al Entero 123. Mi primer pensamiento fue concat pero eso no funciona porque es del tipo incorrecto, he intentado varias cosas, pero por lo general acabo devolviendo la misma lista. Cualquier ayuda muy apreciada.Convierte la lista de enteros en un int (como concat) en haskell

También tengo encontré una forma de imprimir lo correcto (putStr) excepto que quiero que el tipo sea Integer y putStr no lo hace.

Respuesta

21

Puede utilizar foldl combinar todos los elementos de una lista:

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

La función addDigit es llamado por foldl añadir los dígitos, uno tras otro, comenzando desde el extremo izquierdo.

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

Editar:
foldl paseos a través de la lista de izquierda a derecha, la adición de los elementos de acumular un cierto valor.

El segundo argumento de foldl, 0 en este caso, es el valor inicial del proceso. En el primer paso, ese valor inicial se combina con 1, el primer elemento de la lista, llamando al addDigit 0 1. Esto resulta en 10 * 0 + 1 = 1. En el siguiente paso, este 1 se combina con el segundo elemento de la lista, por addDigit 1 2, dando 10 * 1 + 2 = 12. Entonces esto se combina con el tercer elemento de la lista , por addDigit 12 3, resultando en 10 * 12 + 3 = 123.

Entonces, multiplicar inútilmente por cero es solo el primer paso, en los siguientes pasos la multiplicación es realmente necesaria para agregar los nuevos dígitos "hasta el final" del Número acumulado.

+7

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

+0

¡Impresionante! Funciona perfectamente. Esto fue lo que pensé que tendría que hacer, pero lo has hecho mucho mejor de lo que pude, ¡gracias! – Paul

+0

Así que funciona, pero no estoy muy seguro de cómo funciona la pieza addDigit. Sé que foldl toma una función y una lista lo hace en todos los elementos de la lista ... pero addDigit parece multiplicar 0 (num) por 10 y luego agrega el elemento ... que simplemente agregará el elemento ... entonces ¿qué soy? ¿Me pierdo? – Paul

9

Se podría concat las representaciones de cadena de los números, y luego read de vuelta, así:

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

Esto convierte '[12,34]' en '1234', a diferencia de sth, que lo convierte en' 154', o Chris, que se equivoca. El comportamiento deseado de OP no se especifica lo suficiente. – ephemient

+0

sth funciona porque solo uso números de 1 dígito. Esta es también la manera en que me gustaría que funcione ... ¿pero alguien podría explicar con precisión cómo funciona addDigit en sth's? – Paul

2

Uso read y también intToDigit:

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

tiene la ventaja (o desventaja) de vomitar en números de varios dígitos.

0

En cuanto a cómo imprimir el número, en lugar de

putStr n 

sólo trato

putStr (show n) 

El razonamiento es que sólo puede putStr cadenas de impresión. Por lo tanto, debe convertir el número en una cadena antes de pasarlo.

Es posible que también desee probar la función print de Prelude. Este puede imprimir cualquier cosa que sea "visible" (cualquier instancia de la clase Show), no solo cadenas. Pero tenga en cuenta que print n corresponde (aproximadamente) a putStrLn (show n), no a putStr (show n).

+0

Por cierto, esta debería ser una pregunta diferente ... –

1

Otra idea sería decir: el último dígito cuenta para 1, el penúltimo cuenta para 10, el dígito anterior cuenta para 100, etcétera. Por lo tanto, para convertir una lista de dígitos en un número, debe invertirlo (para comenzar desde atrás), multiplicar los dígitos junto con las potencias correspondientes de diez y sumar el resultado.

Para invertir una lista, utilice reverse, para obtener las potencias de diez que puede utilizar iterate (*10) 1 (probarlo en GHCi o abrazos!), Para multiplicar los dígitos correspondientes de dos listas utilizar zipWith (*) y añadir todo junto, utilice sum - ¡realmente ayuda conocer algunas funciones de la biblioteca! Poner los trozos juntos, se obtiene

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

Ejemplo de evaluación:

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 

Sin embargo, esta solución es más lento que los que tienen foldl, debido a la llamada a reverse y ya que estamos construyendo esos poderes de diez solo para usarlos directamente de nuevo. En el lado positivo, esta forma de construir números está más cerca de la forma en que la gente suele pensar (¡al menos yo lo hago!), Mientras que las soluciones foldl en esencia usan Horner's rule.

+0

¿Es esa lista una sintaxis válida en GHC? Todo lo que tengo aquí es Abrazos, y seguro que no funciona allí. – Chuck

+0

No, esa lista es solo para explicar a qué (parte de) se parece el resultado de 'iterate (* 10) 1'. Tampoco funciona en GHC. – yatima2975

-2

No soy un experto en Haskell, pero esta es la forma más fácil que se me ocurre para encontrar una solución a este problema que no implique el uso de otras funciones externas.

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) 

Como puede ver, he supuesto que está tratando de concaturar una lista de dígitos. Si por casualidad este no es tu caso, estoy bastante seguro de que esto no funcionará. :(

En mi solución, en primer lugar he definido una función llamada ReverseDigits, que revierte la lista original. Por ejemplo [1,2,3] a [3,2,1]

Después eso, yo uso una función ConcatReversed que toma una lista de dígitos y el número d, que es el resultado de diez potencias el primer dígito en la posición de la lista. Si la lista está vacía, devuelve 0, y si no, devuelve el primer dígito en la lista de tiempos d, además de la llamada a ConcatReversed pasar el resto de la lista y d veces diez.

esperan que el código de hablar por sí mismo, porque creo que mi pobre explicación Inglés no era muy útil.

+0

-1: las funciones no constructor están en minúsculas. También no es muy intuitiva IMO. –

+0

Creo que esta es una respuesta perfectamente válida. Tenía claro que no soy un experto en Haskell, así que no me maten si no conozco las convenciones de codificación. – Fede

Cuestiones relacionadas