[英]Decide if a list has an even number of elements without counting the number of elements
Implement the
isLengthEven :: [a] -> Bool
function that decides if a list contains an even number of elements.实现
isLengthEven :: [a] -> Bool
函数,该函数决定列表是否包含偶数个元素。 In this exercise, using thelength
function or any other function that returns the number of elements of a list is prohibited.在本练习中,禁止使用
length
函数或任何其他返回列表元素数量的函数。 Hint: All we have to check is whether we can walk the entirety of the list through two by two or does the function miss an item at the very end.提示:我们需要检查的是我们是否可以两两遍历整个列表,或者函数是否在最后遗漏了一个项目。
For example:
isLengthEven "Apple" == True
,isLengthEven "Even" == True
,isLengthEven [] == False
例如:
isLengthEven "Apple" == True
,isLengthEven "Even" == True
,isLengthEven [] == False
So far, I tried pattern matching and recursion, which is in my opinion the optimal way of doing this exercise.到目前为止,我尝试了模式匹配和递归,在我看来,这是进行此练习的最佳方式。 My code is as follows:
我的代码如下:
isLengthEven :: [a] -> Bool
isLengthEven [] = False
isLengthEven (x:[]) = False
isLengthEven (x:(y:[])) = True
isLengthEven (x:(y:(z:[]))) = False
isLengthEven (x:(y:(z:(q:[])))) = True
isLengthEven (x:xs) = isLengthEven (xs)
This returns the correct values up until I insert the fifth element into the list.这将返回正确的值,直到我将第五个元素插入列表中。 It returns
True
for any number of elements above or equal to 5. I suppose there's a problem with the recursion part.对于大于或等于 5 的任意数量的元素,它返回
True
。我想递归部分有问题。
You need only two base cases here:您在这里只需要两个基本情况:
0
and thus should return True
;0
,因此应该返回True
; and The recursive cases each time move two steps forward in the list, so:递归情况每次在列表中向前移动两步,因此:
isLengthEven :: [a] -> Bool
isLengthEven [] = True
isLengthEven [x] = False
isLengthEven (_:_:xs) = isLengthEven xs
Often one defines two functions: isLengthEven
and isLengthOdd
and thus these functions each time call each other recursively with:通常定义两个函数:
isLengthEven
和isLengthOdd
,因此这些函数每次都以递归方式相互调用:
isLengthEven :: [a] -> Bool
isLengthEven [] = True
isLengthEven (_:xs) =
isLengthOdd xs
isLengthOdd :: [a] -> Bool
isLengthOdd [] = False
isLengthOdd (_:xs) =
isLengthEven xs
Note that the excellent answer by Willem is already an optimized one.请注意, Willem的优秀答案已经是优化的答案。
If you prefer a straight unoptimized version and choose to disregard the hint, you can do with just the first and last clauses of your initial code.如果您更喜欢未经优化的直接版本并选择忽略提示,则可以仅使用初始代码的第一个和最后一个子句。 Like this:
像这样:
-- warning: the following is incorect, needs changes:
isLengthEven :: [a] -> Bool
isLengthEven [] = False
isLengthEven (x:xs) = isLengthEven (xs)
Both clauses are incorrect, but it is easy to fix them:这两个子句都不正确,但很容易修复它们:
isLengthEven :: [a] -> Bool
isLengthEven [] = True
isLengthEven (x:xs) = not (isLengthEven xs)
and taken together, these two clauses cover all possible situations.综合起来,这两个条款涵盖了所有可能的情况。
As is, this function uses a lot of stack space for long inputs.照原样,此函数为长输入使用了大量堆栈空间。 This can be fixed thru the common argument-as-accumulator trick.
这可以通过常见的参数作为累加器技巧来解决。 Here:
这里:
isLengthEven :: [a] -> Bool
isLengthEven xs = go True xs where
go b [] = b
go b (x:xs) = go (not b) xs
where the go
auxiliary stepping function is tail-recursive.其中
go
辅助步进函数是尾递归的。
With that change, my machine is getting 67% of the performance of the obvious but prohibited (even (length xs))
solution.通过这种变化,我的机器获得了明显但被禁止
(even (length xs))
解决方案的 67% 的性能。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.