2010-06-18 5 views

Répondre

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

Si vous voulez traiter de longueur impaire il suffit d'ajouter cnv [x] = variante avant dernière

+1

Pouvez-vous expliquer ces lignes de code cnv (k: v: t) = (k, lire v): cnv t? AFAIK, le k v t est un paramètre de la liste k est la tête et v est la queue et cnv t est l'élément suivant comme k. Est-ce que ma compréhension est correcte parce qu'avant j'ai fonctionné comme ceci. Convert :: [chaîne] -> \t [(String, Integer)] convertir [] = [] convert (x: Y: xs) = (x, y) convertir xs et pourquoi quand j'ajouter: xs ça ne marche pas? Est-ce que k v t représente un seul élément de la liste ou de la liste entière? – peterwkc

+3

Pas tout à fait: dans 'k: v: t',' k' est la tête, et 'v: t' est la queue. Ainsi, 'k: v: t' place les deux premiers éléments de la liste dans' k' et 'v' et la queue restante dans' t'. Votre code a deux problèmes évidents: (a) '(x, y)' a le type '(String, String)', pas '(String, Integer)'; et (b) il n'y a pas deux points avant 'convert xs'. (Vous ne pouvez pas simplement faire ': xs', car vous avez besoin de [[(String, Integer)]' mais 'xs' a le type' [String] '.) Aussi, un conseil de mise en forme: indentation des lignes avec quatre espaces obtenir des blocs de code (ou sélectionnez votre code et cliquez sur le bouton "101010"), et des extraits de code surround avec des guillemets (\ '... code ... \'). –

+0

(x: xs) Cela signifie que x est la tête et l'élément restant est la queue pour xs. Merci pour votre explication. – peterwkc

8

ony's solution est un peu plus court, mais voici une version non récurrente en utilisant splitEvery de la split library très pratique:

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

Les étapes ici sont quelque peu plus claires (pour moi, au moins) que dans la version récursive.

+2

Ceci est certainement plus naturel. La bibliothèque fractionnée ne reçoit pas assez d'amour. C'est dommage, car c'est incroyablement utile. –

+0

Notez que 'splitEvery' semble être obsolète maintenant; utilisez plutôt ['chunksOf'] (https://hackage.haskell.org/package/split-0.2.2/docs/Data-List-Split.html#v:chunksOf) à la place. – sevko

3

Exactement pour une tâche comme cela, je trouve qu'il est commode d'avoir une fonction stride de prendre tous les éléments n-ième de la liste:

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

Il peut être utilisé pour convertir une liste de paires:

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

Un exemple (notez que le dernier élément peut être jeté si elle ne dispose pas de paire):

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

Il peut même être facilement étendu à des triplés ou tuples plus:

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

Pour effectuer la conversion de String à l'entier dans votre exemple, vous pouvez affecter la fonction read sur la deuxième foulée:

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

qui donne:

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