简体   繁体   English

反转 Haskell 列表中的每个偶数元素

[英]Reverse every even element in Haskell list

In Haskell a list is given, but you should reverse every even element.在 Haskell 中给出了一个列表,但您应该反转每个偶数元素。 For example the list例如列表

f ["rehtruF", "dooG", kcuL"]

should be changed into应该改成

["Further", "Good" "Luck"]

We tried this function:我们试过这个 function:

f [] = []
f [x] = []
f (xs:ys:xss) = (reverse xs):(f xss)

but unfortunately, it only reversed the first element and prints it out.但不幸的是,它只反转了第一个元素并将其打印出来。 Do you have any idea how we could change the code, so that every even element is reserved and the output is as demonstrated above?您知道我们如何更改代码,以便保留每个偶数元素,并且 output 如上所示?

TL;DR - this is the solution (based on this answer ) that Thomas M. DuBuisson alluded to in his comment. TL;DR - 这是 Thomas M. DuBuisson 在他的评论中提到的解决方案(基于这个答案)。 Oops.哎呀。


You don't even need to explicitly iterate over the input.您甚至不需要显式地迭代输入。 Imagine you had a list of functions fs = [f0, f1, f2, ...] and a list of values xs = [x0, x1, x2, ...] , and you want to get [f0 x0, f1 x1, f2 x2, ...] .想象一下,你有一个函数列表fs = [f0, f1, f2, ...]和一个值列表xs = [x0, x1, x2, ...] ,你想得到[f0 x0, f1 x1, f2 x2, ...] You do that with zipWith ($) :你用zipWith ($)做到这一点:

zipWith ($) fs xs  -- == [f0 $ x0, f1 $ x1, f2 $ x2, ...]
                   -- == [f0 x0, f1 x1, f2 x2, ...]

For your problem, your fs would be an alternating sequence of reverse and id , which you can produce with cycle [reverse, id] == [reverse, id, reverse, id, ...]对于您的问题,您的fs将是reverseid的交替序列,您可以使用cycle [reverse, id] == [reverse, id, reverse, id, ...]

Putting this together,把这个放在一起,

f :: [String] -> [String]
f strings = zipWith ($) (cycle [reverse, id]) strings
        -- == [reverse strings0, id strings0, reverse strings2, id strings3, ...]

or simply或者干脆

f :: [String] -> [String]
f = zipWith ($) (cycle [reverse, id])

The problem is that you completely drop the ys element.问题是您完全删除了ys元素。 What you actually want is keep it as-is , ie put it as-is in the result list.你真正想要的是保持原样,即把它原样放在结果列表中。

f (xs:ys:xss) = reverse xs : ys : f xss

Note that GHC would have warned you about the unused ys binding, if you had turned on the -Wall option (which is generally a good idea for beginners).请注意,如果您打开了-Wall选项,GHC 会警告您未使用的ys绑定(这对于初学者来说通常是个好主意)。 You can do that by executing the compiler/interpreter with ghc -Wall YOURFILE.hs , or by typing :set -Wall in a GHCi session.您可以通过使用ghc -Wall YOURFILE.hs执行编译器/解释器或在 GHCi session 中键入:set -Wall来做到这一点。

To reverse the even elements in the list, the first thing is to find even elements, one of the ways to do that is to index each elements in the list firstly like:要反转列表中的偶数元素,首先要找到偶数元素,其中一种方法是首先索引列表中的每个元素,例如:

zip [0..] xs

and then, we reverse the elements has even index:然后,我们反转具有偶数索引的元素:

if index `mod` 2 == 0 then reverse x else x

put them all as把它们都当作

f xs = map reverseEven (zip [0..] xs)
    where reverseEven (index, x) = if index `mod` 2 == 0 
                                   then reverse x else x

One ought not to calculate anything that doesn't need calculating.一个人不应该计算任何不需要计算的东西。 No zipping, no cycling, no mod taking, just pure function calling :没有拉链,没有骑行,没有改装,只是纯粹的 function 调用mod

foo :: [[a]] -> [[a]]
foo xs = foldr (\ x r f g -> f x (r g f)) 
               (\ _ _ -> []) 
               xs 
               ((:) . reverse) 
               (:)

First element is considered to be at index 0, ie at even position, as is in the question.第一个元素被认为在索引 0 处,即甚至在 position 处,如问题所示。

> foo ["Further","Good","Luck"]
["rehtruF","Good","kcuL"]

> foo $ foo ["Further","Good","Luck"]
["Further","Good","Luck"]

With plain recursion, what the above foldr -based definition is doing is:通过简单的递归,上面基于foldr的定义正在做的是:

foo = f   where 
      f (x:xs)  =  reverse x : g xs
      g (x:xs)  =  x : f xs 

, plus the obvious [] -handling cases. ,加上明显的[]处理案例。

With foldr , [] is checked for by foldr itself;使用foldr[]foldr本身检查; with mutual recursion, it must be done by each of the two cooperating functions.对于相互递归,它必须由两个协作函数中的每一个来完成。

If you add an extra variable, you can keep track if you are on an even element or an odd element.如果您添加一个额外的变量,您可以跟踪您是在偶数元素还是奇数元素上。 For example, here we are using 1 to mean odd and 0 to mean even:例如,这里我们使用1表示奇数,使用0表示偶数:

f = f' 1
  where
    f' _ []     = []
    f' 1 (x:xs) = reverse x: f' 0 xs
    f' 0 (x:xs) = x: f' 1 xs

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

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