у меня есть список как это
["peter","1000","michell","2000","kelly","3000"]
и я хотел бы преобразовать в
[("peter",1000),("michell", 2000),("kelly",3000)]
Помогите.Спасибо.
cnv :: [String] -> [(String, Integer)]
cnv [] = []
cnv (k:v:t) = (k, read v) : cnv t
Если вы хотите обрабатывать нечетную длину, просто добавьте cnv [x] =
вариант перед последним
Именно для такой задачи я считаю удобным иметь функцию stride
, которая берет каждый n-й элемент из списка:
stride _ [] = []
stride n (x:xs) = x : stride n (drop (n-1) xs)
Ее можно использовать для преобразования списка в пары:
toPairs xs = zip (stride 2 xs) (stride 2 (drop 1 xs))
Пример (обратите внимание, что последний элемент может быть отброшен, если у него нет пары):
ghci> stride 2 [1..5]
[1,3,5]
ghci> toPairs [1..7]
[(1,2),(3,4),(5,6)]
Его можно даже легко расширить до триплетов или более длинных кортежей:
toTriplets xs = zip3 as bs cs
where as = stride 3 xs
bs = stride 3 $ drop 1 xs
cs = stride 3 $ drop 2 xs
Чтобы выполнить преобразование из String
в целое число в вашем примере, вы можете сопоставить функцию read
на втором шаге:
let lst = ["peter","1000","michell","2000","kelly","3000"] in
zip (stride 2 lst) (map read . stride 2 . drop 1 $ lst) :: [(String,Int)]
, что дает:
[("peter",1000),("michell",2000),("kelly",3000)]
Единственное решение немного короче, но вот нерекурсивная версия, использующая splitEvery
из очень удобной библиотеки split
:
cnv = map (\[name, amount] -> (name, read amount :: Int)) . splitEvery 2
Шаги здесь несколько понятнее (по крайней мере для меня), чем в рекурсивной версии.