Haskell如何比对列表全量元素并返回重复的二元组元素
问题解决思路与实现
原代码问题分析
- 终止条件错误:单元素列表没有后续元素可比对,本不应返回,你当前的逻辑会直接把最后一个元素加入结果,导致输出异常。
- 递归逻辑缺陷:你每次递归始终保留第一个元素
x在列表头部,只会用第一个元素和后续内容比对,无法移动基准元素到第二个、第三个位置完成全量比对。
实现方案
方案1:计数过滤法(推荐,逻辑简洁性能好)
通过统计每个元素的出现次数,直接展开得到所有重复元素,完全符合你的预期输出:
import qualified Data.Map as Map test :: (Eq a, Ord a) => [(a,a)] -> [(a,a)] test lst = concat [replicate count val | (val, count) <- Map.toList countMap, count >= 2] where countMap = Map.fromListWith (+) [(item, 1) | item <- lst]
输入你给出的示例列表[(1,2),(3,9),(7,9),(6,4),(1,2),(4,2),(3,9),(1,2)],输出结果为[(1,2),(1,2),(1,2),(3,9),(3,9)],和预期完全一致。
方案2:逐位比对实现(符合你要求的比对逻辑,无额外依赖)
如果你需要严格按照「每个元素和后续所有元素比对」的逻辑实现,不需要导入第三方库,可以用以下写法:
-- 辅助函数:判断元素是否在列表中存在 elemIn :: Eq a => (a,a) -> [(a,a)] -> Bool elemIn _ [] = False elemIn target (x:xs) = target == x || elemIn target xs -- 自定义tails函数,拆分列表为所有后缀 splitTails :: [a] -> [[a]] splitTails [] = [[]] splitTails l@(_:rest) = l : splitTails rest test :: Eq a => [(a,a)] -> [(a,a)] test lst = concat [replicate (1 + length (filter (== cur) rest)) cur | (cur:rest) <- splitTails lst, cur `elemIn` rest]
原代码调整参考
如果要基于你现有的代码修改,核心调整两点:
- 终止条件改为
test [] = []、test [_] = [],单元素无重复直接返回空 - 完成第一个元素和所有后续元素的比对后,递归处理去掉第一个元素的剩余列表,而不是一直保留第一个元素在头部
内容的提问来源于stack exchange,提问作者sinNombre
相关产品推荐
相关产品推荐

