Получить первые элементы списка кортежей
У меня есть этот список кортежей
[(4,'a'), (1,'b'), (2,'c'), (2,'a'), (1,'d'), (4,'e')]
Я хочу получить первые элементы каждого кортежа, а затем скопировать его, чтобы сделать следующее: "aaaabccaadeeee"
Я придумал этот код, но он дает мне только копию первого кортежа.
replicate (fst ( head [(4,'a'), (1,'b')])) ( snd ( head [(4,'a'), (1,'b')]))
--output is: "aaaa"
Я думал использовать карту для получения копии каждого кортежа, но мне это не удалось.
3 ответа
Поскольку вы уже знаете, как найти правильный ответ для отдельного элемента, все, что вам нужно, это небольшая рекурсия
func :: [(Int, a)] -> [a]
func [] = []
func ((n, elem):rest) = (replicate n elem) ++ (func rest)
Отображение значений также должно работать. Вам просто нужно объединить полученные строки в одну.
func :: [(Int, a)] -> [a]
func xs = concat $ map func2 xs where
func2 (n, elem) = replicate n elem
Или, если вы знакомы с карри:
func :: [(Int, a)] -> [a]
func xs = concat $ map (uncurry replicate) xs
Наконец, если вам удобно использовать композицию функций, определение становится следующим:
func :: [(Int, a)] -> [a]
func = concat . map (uncurry replicate)
С помощью concat
а также map
это так часто, есть функция, чтобы сделать это. Это concatMap
,
func :: [(Int, a)] -> [a]
func = concatMap (uncurry replicate)
Позволять
ls = [(4,'a'), (1,'b'), (2,'c'), (2,'a'), (1,'d'), (4,'e')]
в
concat [replicate i x | (i, x) <- ls]
дам
"aaaabccaadeeee"
Бессмысленная версия
concat . map (uncurry replicate)
Вы правы, пытаясь использовать map
, Но сначала давайте посмотрим, почему ваш код не работал
replicate (fst ( head [(4,'a'), (1,'b')])) ( snd ( head [(4,'a'), (1,'b')]))
Ваш первый параметр для репликации - это заголовок вашего списка (4, "а"). Затем вы вызываете fst для этого, таким образом, первый параметр равен 4. То же самое происходит со вторым параметром, и вы получаете "a". Результат, который вы видите.
Перед использованием map
давайте попробуем сделать это с помощью рекурсии. Вы хотите взять один элемент списка и применить реплику к нему, а затем объединить его с результатом применения репликации ко второму элементу.
generate [] = []
generate (x:xs) = replicate (fst x) (snd x) ++ generate xs
Заметьте, я использую сопоставление с образцом, чтобы получить первый элемент списка. Вы можете использовать сопоставление с шаблоном, чтобы получить элемент внутри кортежа, и тогда вам не нужно будет использовать функции fst / snd. Также обратите внимание, что я использую сопоставление с образцом, чтобы определить базовый случай пустого списка.
generate [] = []
generate ((x,y):xs) = replicate x y ++ generate xs
Теперь перейдем к карте, поэтому карта будет применять вашу функцию к каждому элементу списка, вот первая попытка
generate (x,y) = replicate x y
map generate xs
Результат выше будет немного отличаться от рекурсии. Подумайте об этом, карта будет применять генерировать к каждому элементу и сохранить результат в списке. Сгенерировать создает список. Поэтому, когда вы применяете карту, вы создаете список списка. Вы можете использовать concat для выравнивания, если хотите, что даст тот же результат, что и рекурсия.
И последнее, если вы можете использовать рекурсию, то вы также можете использовать сложение. Fold просто применяет функцию к каждому элементу списка и возвращает накопленные результаты (в общем).
--first parameter is the function to apply, second is the accumulator, third is your list
foldr step [] xs
where step (x,y) acc =
(replicate x y) ++ acc
Здесь я снова использовал сопоставление с образцом на шаге функции для извлечения элементов кортежа.