Получить первые элементы списка кортежей

У меня есть этот список кортежей

[(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

Здесь я снова использовал сопоставление с образцом на шаге функции для извлечения элементов кортежа.

Другие вопросы по тегам