如何统计数字列表中的奇偶个数?Haskell函数实现求助
解决Haskell列表奇偶次数统计问题
嘿,我来帮你搞定这个统计数字列表奇偶次数的需求~先看看你现有代码里的小问题,再给你几种靠谱的实现方案:
现有代码的几个小问题
- 奇偶判断逻辑有误:你用
div来判断偶数是不可靠的,比如负数-2,-2div2会得到-1,不等于0,这就会把它错误判定成奇数。正确的做法应该用mod运算符,xmod2 == 0才是判断偶数的准确方式。 - 代码冗余:分开写
counteven和countodd需要两次遍历列表,其实可以优化成一次遍历搞定,效率更高。 - 未完成核心函数:你的
oddsAndEvens只写了一半函数头,还需要补全实现才能返回预期的元组结果。
修正&优化后的实现
方案1:基于你现有代码补全
先修正counteven和countodd的判断逻辑,再完成oddsAndEvens:
counteven :: [Integer] -> Integer counteven [] = 0 counteven (x:xs) | x `mod` 2 == 0 = 1 + counteven xs | otherwise = counteven xs countodd :: [Integer] -> Integer countodd [] = 0 countodd (x:xs) | x `mod` 2 /= 0 = 1 + countodd xs | otherwise = countodd xs oddsAndEvens :: [Integer] -> (Integer, Integer) oddsAndEvens xs = (counteven xs, countodd xs)
测试一下你给的例子:
-- 输入[1,2,3,4,5],会返回(2,3),完全符合你的预期 oddsAndEvens [1,2,3,4,5]
方案2:一次遍历的高效实现
上面的方案需要两次遍历列表,对于大型数据来说有点浪费。我们可以用递归或者折叠函数,一次遍历就统计出两个计数:
递归版本
oddsAndEvens :: [Integer] -> (Integer, Integer) -- 空列表的情况,奇偶计数都是0 oddsAndEvens [] = (0, 0) -- 处理每个元素,递归更新计数 oddsAndEvens (x:xs) | x `mod` 2 == 0 = let (evens, odds) = oddsAndEvens xs in (evens + 1, odds) | otherwise = let (evens, odds) = oddsAndEvens xs in (evens, odds + 1)
折叠(foldl)版本(更简洁)
oddsAndEvens :: [Integer] -> (Integer, Integer) oddsAndEvens = foldl count (0, 0) where count (evens, odds) x | x `mod` 2 == 0 = (evens + 1, odds) | otherwise = (evens, odds + 1)
这个折叠版本代码更紧凑,而且只遍历一次列表,性能是最优的。
小提示
一定要用mod而不是div来判断奇偶,因为mod能正确处理负数的情况——比如(-4) mod 2结果是0,会被正确判定为偶数;而(-4) div 2是-2,不等于0,会直接出错哦。
内容的提问来源于stack exchange,提问作者Amy
相关产品推荐
相关产品推荐

