[英]Take elements on even positions from the list
问题:使用折叠 ,从偶数位置的列表元素中获取:
GHCi> evenOnly [1..10]
[2,4,6,8,10]
GHCi> evenOnly ['a'..'z']
"bdfhjlnprtvxz"
evenOnly :: [a] -> [a]
evenOnly = undefined
我最初决定得到0
-es和1
-s的交替列表: [0,1,0,1..]
Prelude> let g = iterate (\x -> (x + 1) `mod` 2) 0
Prelude> take 10 $ g
[0,1,0,1,0,1,0,1,0,1]
然后用原始列表压缩它,获得对的列表: [(x1, 0), (x2,1), (x3,0) .. (xn, ?)]
:
Prelude> zip g [1,2,3,4,5]
[(0,1),(1,2),(0,3),(1,4),(0,5)]
之后,将带有过滤功能和空列表的对列表foldr
为初始化值。
所以我认为这样可行:
evenOnly :: [a] -> [a]
evenOnly xs = let g = iterate (\x -> (x + 1) `mod` 2) 0
in
foldr (\ (x, n) s -> if n == 1 then x : s else s) [] . (zip g xs)
但它给出了一个错误,我不明白:
foldr.hs:44:59: error:
• Couldn't match expected type ‘a0 -> t0 (a1, Integer)’
with actual type ‘[(Integer, a)]’
• Possible cause: ‘zip’ is applied to too many arguments
In the second argument of ‘(.)’, namely ‘(zip g xs)’
In the expression:
foldr (\ (x, n) s -> if n == 1 then x : s else s) [] . (zip g xs)
In the expression:
let g = iterate (\ x -> (x + 1) `mod` 2) 0
in
foldr (\ (x, n) s -> if n == 1 then x : s else s) [] . (zip g xs)
• Relevant bindings include
xs :: [a] (bound at foldr.hs:42:10)
evenOnly :: [a] -> [a] (bound at foldr.hs:42:1)
我认为我的想法是正确的,我只是做了一些错误的语法。
(.)
是函数组合,但zip g xs
是列表而不是函数。 您可以直接将结果列表作为参数应用于foldr
。 请注意,您的参数g
和xs
的顺序错误:
evenOnly :: [a] -> [a]
evenOnly xs = let g = iterate (\x -> (x + 1) `mod` 2) 0
in
foldr (\ (x, n) s -> if n == 1 then x : s else s) [] (zip xs g)
模式匹配是一种非常合理的方法:
evenOnly :: [a] -> [a]
evenOnly (_ : a : as) = a : evenOnly as
evenOnly _ = []
另一种选择是使用列表理解:
evenOnly as = [a | (a, True) <- zip as (cycle [False, True])]
如果与其他列表处理函数融合,列表推导版本可能会更有效。
一个人不应该计算任何不需要计算的东西。 选择是位置,它已经提前知道。 与布尔运算相比,计算模数是多余的工作。
相反, 这样做,那么做 ,再这样下去的切换; 使用foldr
,问:
evenly :: [t] -> [t]
evenly xs = foldr c z xs f g
where
c x r f g = f x (r g f)
接下来,我们根据每种方法的使用方式完成定义:
z _ _ = []
f _ xs = xs
g x xs = x : xs
您可以将上面的数字与一系列数字一起zip
,例如:
evenOnly :: [a] -> [a]
evenOnly = foldr (\(c, x) -> if c then (x:) else id) [] . zip (cycle [False, True])
这里cycle [False, True]
因此生成[False, True, False, True, …]
的无限列表。 在foldr
我们检查源自cycle [False, True]
的相应值c
。 如果它是True
,那么我们在列表前加上x
,否则我们只传递带有id
的递归调用的结果。
或者我们可以省略这个,并使用:
evenOnly :: [a] -> [a]
evenOnly = foldr (uncurry ($)) [] . zip (cycle [const id, (:)])
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.