2010-06-18 18 views
7

tengo una lista como estaHaskell lista de lista de tuplas

["peter","1000","michell","2000","kelly","3000"] 

y me gustaría convertir a

[("peter",1000),("michell", 2000),("kelly",3000)] 

Por favor, ayuda. Gracias.

Respuesta

13
cnv :: [String] -> [(String, Integer)] 
cnv [] = [] 
cnv (k:v:t) = (k, read v) : cnv t 

Si desea manejar impar de longitud sólo tiene que añadir cnv [x] = variante antes última

+1

¿Puede explicar estas líneas de código cnv (k: v: t) = (k, leer v): cnv t? AFAIK, el k v t es un parámetro de la lista k es la cabeza yv es la cola y cnv t es el siguiente elemento como k. Es mi entendimiento correcto porque previamente tengo una función como esta. convertido :: [String] -> \t [(String, Integer)] convertido [] = [] convert (x: y: x) = (x, y) convertir XS y por qué cuando agrego: xs no está funcionando? ¿El k v t representa un solo elemento en la lista o lista completa? – peterwkc

+3

No exactamente: en 'k: v: t',' k' es la cabeza, y 'v: t' es la cola. Por lo tanto, 'k: v: t' coloca los primeros dos elementos de la lista en' k' y 'v' y la cola restante en' t'. Su código tiene dos problemas obvios: (a) '(x, y)' tiene tipo '(String, String)', not '(String, Integer)'; y (b) no hay dos puntos antes de 'convert xs'. (No puede hacer ': xs', porque necesita' [(String, Integer)] 'pero' xs' tiene tipo '[String]'.) Además, un consejo de formateo: sangría las líneas con cuatro espacios en blanco para obtener bloques de código (o seleccionar su código y hacer clic en el botón "101010"), y rodear los fragmentos de código con barras invertidas (\ '... código ... \'). –

+0

(x: xs) Eso significa que x es la cabeza y el resto del elemento es cola para xs. Gracias por su explicación. – peterwkc

8

ony's solution es un poco más corto, pero aquí es una versión no recursiva utilizando splitEvery de la muy práctico split library:

cnv = map (\[name, amount] -> (name, read amount :: Int)) . splitEvery 2 

Los pasos aquí son algo más claros (para mí, al menos) que en la versión recursiva.

+2

Esto es definitivamente más natural. La biblioteca dividida no recibe suficiente amor. Es una lástima, ya que es increíblemente útil. –

+0

Tenga en cuenta que 'splitEvery' parece estar en desuso ahora; utilice ['chunksOf'] (https://hackage.haskell.org/package/split-0.2.2/docs/Data-List-Split.html#v:chunksOf) en su lugar. – sevko

3

Exactamente para una tarea como esta me parece conveniente tener una función stride tomar cada elemento n-ésimo de la lista:

stride _ [] = [] 
stride n (x:xs) = x : stride n (drop (n-1) xs) 

Se puede utilizar para convertir una lista de pares:

toPairs xs = zip (stride 2 xs) (stride 2 (drop 1 xs)) 

Un ejemplo (tenga en cuenta que el último elemento puede ser desechado si no tiene pareja):

ghci> stride 2 [1..5] 
[1,3,5] 
ghci> toPairs [1..7] 
[(1,2),(3,4),(5,6)] 

Puede ser incluso extender fácilmente a trillizos o tuplas más largos:

toTriplets xs = zip3 as bs cs 
    where as = stride 3 xs 
     bs = stride 3 $ drop 1 xs 
     cs = stride 3 $ drop 2 xs 

Para llevar a cabo la conversión de String al número entero en su ejemplo, puede asignar read función sobre el segundo paso:

let lst = ["peter","1000","michell","2000","kelly","3000"] in 
zip (stride 2 lst) (map read . stride 2 . drop 1 $ lst) :: [(String,Int)] 

cuales da:

[("peter",1000),("michell",2000),("kelly",3000)] 
Cuestiones relacionadas