Pus*_*yon 0 haskell functional-programming
我想创建一个函数,从int的列表返回每个第三个int而不使用任何预定义的函数.例如,everyThird [1,2,3,4,5] --> [1,4]
everyThird:: [a] -> [a]
Run Code Online (Sandbox Code Playgroud)
我可以继续使用tail迭代列表并每隔三次调用追加到一个新列表吗?我是Haskell的新手并且对所有这些感到非常困惑
另一种方法是处理三种不同的基本情况,在所有这些基本情况下,我们位于列表的末尾,列表长度少于三个元素,以及一个递归情况,其中列表至少有三个元素长:
everyThird :: [a] -> [a]
everyThird [] = []
everyThird [x] = [x]
everyThird [x, _] = [x]
everyThird (x:_:_:xs) = x:everyThird xs
Run Code Online (Sandbox Code Playgroud)
您希望完全按照您的说法执行操作:遍历列表并仅在每次第三次调用时包含元素.但是,有一个问题.Haskell是一种有趣的语言,其中"改变"变量的想法没有意义,所以通常的方法"有一个反向变量i告诉我们我们是否在第三个元素上"将无法在通常的方式.相反,我们将创建一个递归辅助函数来维护我们的计数.
everyThird :: [Int] -> [Int]
everyThird xs = helper 0 xs
where helper _ [] = []
helper 0 (x : xs) = x : helper 2 xs
helper n (_ : xs) = helper (n - 1) xs
Run Code Online (Sandbox Code Playgroud)
我们在帮手中有三个案例.
由于模式匹配的工作方式,它将按顺序尝试这三个语句.
注意我们如何使用另一个参数作为计数器变量,因为我们不能像在命令式语言中那样改变变量.另外,请注意我们如何递归地构造列表; 我们永远不会"追加"到现有列表,因为这意味着我们正在改变列表.我们只是从头开始构建列表,并在第一轮结束时得到正确的结果.
Haskell没有经典迭代(即没有循环),至少没有monad,但你可以使用类似的逻辑,就像你在for循环中使用索引压缩列表[0..]并从Data.List应用适当的函数.
例如,您需要做的是过滤每第三个元素:
everyThirdWithIndexes list = filter (\x -> snd x `mod` 3 == 0) $ zip list [0..]
Run Code Online (Sandbox Code Playgroud)
当然你必须摆脱索引,有两种优雅的方法可以做到这一点:
everyThird list = map (fst) . everyThirdWithIndexes list
-- or:
everyThird list = fst . unzip . everyThirdWithIndexes list
Run Code Online (Sandbox Code Playgroud)
如果你不熟悉filter和map,你可以定义一个简单的递归,它从列表的每个第一个元素构建一个列表,删除接下来的两个,然后从一个新的函数调用中添加另一个:
everyThird [] = [] -- both in case if the list is empty and the end case
everyThird (x:xs) = x : everyThird (drop 2 xs)
Run Code Online (Sandbox Code Playgroud)
编辑:如果您对这些解决方案有任何疑问(例如您不熟悉的一些语法),请随时在评论中提问.:)
一种经典方法:
everyThird xs = [x | (1,x) <- zip (cycle [1..3]) xs]
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
678 次 |
| 最近记录: |