Получить первые элементы списка кортежей - PullRequest
0 голосов
/ 16 ноября 2018

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

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

0 голосов
/ 16 ноября 2018

Вы правы, пытаясь использовать map. Но сначала давайте посмотрим, почему ваш код не работал

replicate  (fst ( head [(4,'a'), (1,'b')])) ( snd ( head [(4,'a'), (1,'b')]))

Ваш первый параметр для репликации - это заголовок вашего списка (4, 'a'). Затем вы вызываете 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

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

0 голосов
/ 16 ноября 2018

Пусть

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) 
0 голосов
/ 16 ноября 2018

Поскольку вы уже знаете, как найти правильный ответ для отдельного элемента, все, что вам нужно, это небольшая рекурсия

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

Или, если вы знакомы с curry :

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)
...