简体   繁体   English

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

[英]Take elements on even positions from the list

Problem: using fold , take from the list elements which are on the even positions: 问题:使用折叠 ,从偶数位置的列表元素中获取:

GHCi> evenOnly [1..10]
 [2,4,6,8,10]
GHCi> evenOnly ['a'..'z']
 "bdfhjlnprtvxz"

evenOnly :: [a] -> [a]
evenOnly = undefined

I decided at first to get a list of alternating 0 -es and 1 -s: [0,1,0,1..] 我最初决定得到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]

Then zip it with the original list, getting a list of pairs: [(x1, 0), (x2,1), (x3,0) .. (xn, ?)] : 然后用原始列表压缩它,获得对的列表: [(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)]

After that, foldr the list of pairs with a filtering function and an empty list as initialization value. 之后,将带有过滤功能和空列表的对列表foldr为初始化值。

So I thought that this would work: 所以我认为这样可行:

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)

But it gives an error, that I don't understand: 但它给出了一个错误,我不明白:

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)

I think my idea is correct, I just did something wrong with the syntax. 我认为我的想法是正确的,我只是做了一些错误的语法。

(.) is function composition but zip g xs is a list not a function. (.)是函数组合,但zip g xs是列表而不是函数。 You can just apply the resulting list as the argument to foldr directly. 您可以直接将结果列表作为参数应用于foldr Note you have the arguments g and xs in the wrong order: 请注意,您的参数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)

Pattern matching is a perfectly reasonable approach: 模式匹配是一种非常合理的方法:

evenOnly :: [a] -> [a]
evenOnly (_ : a : as) = a : evenOnly as
evenOnly _ = []

Another option is to use a list comprehension: 另一种选择是使用列表理解:

evenOnly as = [a | (a, True) <- zip as (cycle [False, True])]

The list comprehension version will likely be a bit more efficient if it fuses with other list processing functions. 如果与其他列表处理函数融合,列表推导版本可能会更有效。

One ought not to calculate anything that doesn't need calculating. 一个人不应该计算任何不需要计算的东西。 The choice is positional, it is already known in advance. 选择是位置,它已经提前知道。 Calculating the modulos, comparing with Booleans, is all superfluous work. 与布尔运算相比,计算模数是多余的工作。

Instead, do this , then do that , and go on switching like that; 相反, 这样做,那么 ,再这样下去的切换; using foldr , as asked: 使用foldr ,问:

evenly :: [t] -> [t]
evenly xs = foldr c z xs f g
   where
   c x r f g = f x (r g f)

Next we finish up the definitions, according to how each is used: 接下来,我们根据每种方法的使用方式完成定义:

   z _ _  = []
   f _ xs = xs
   g x xs = x : xs

You can just zip the above together with a sequence of numbers, like: 您可以将上面的数字与一系列数字一起zip ,例如:

evenOnly :: [a] -> [a]
evenOnly = foldr (\(c, x) -> if c then (x:) else id) [] . zip (cycle [False, True])

Here cycle [False, True] thus generates an infinite list of [False, True, False, True, …] . 这里cycle [False, True]因此生成[False, True, False, True, …]的无限列表。 In the foldr we check the corresponding value c that originates from the cycle [False, True] . foldr我们检查源自cycle [False, True]的相应值c If it is True , then we prepend the list with x , otherwise we just pass the result of the recursive call with id . 如果它是True ,那么我们在列表前加上x ,否则我们只传递带有id的递归调用的结果。

Or we can omit this, and use: 或者我们可以省略这个,并使用:

evenOnly :: [a] -> [a]
evenOnly = foldr (uncurry ($)) [] . zip (cycle [const id, (:)])

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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