我有这个元组列表
[(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"
我当时正在考虑使用map来获取每个元组的副本,但是我没有成功。
答案 0 :(得分:5)
由于您已经知道如何为单个元素找到正确的答案,因此您只需要进行一点递归
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
或者,如果您熟悉currying:
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)
答案 1 :(得分:1)
您对尝试使用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
现在要映射,因此map会将您的函数应用于列表的每个元素,这是第一次尝试
generate (x,y) = replicate x y
map generate xs
以上结果与递归略有不同。考虑一下,map将对每个元素应用generate并将结果存储在列表中。 generate创建一个列表。因此,当您应用地图时,您将创建一个列表列表。您可以根据需要使用concat对其进行展平,这将为您提供与递归相同的结果。
最后,如果可以使用递归,那么也可以使用fold。 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
再次在这里,我在功能步骤中使用了模式匹配,以提取出元组的元素。
答案 2 :(得分:1)
让我们
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)