繁体   English   中英

从列表中获取偶数位置的元素

[英]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 请注意,您的参数gxs的顺序错误:

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM