You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Haskell列表合并问题:按配对首元素合并同键列表

解决Haskell列表分组拼接的问题

嘿,刚入门Haskell遇到这种分组拼接的问题很正常,我来帮你理清楚思路,以及你之前尝试不对的原因~

首先,你的需求是把首元素(也就是那些(0,1)、(1,2)这样的键)相同的元组里的列表拼接起来,核心步骤其实是两个:按首元素分组 + 拼接每个组里的所有列表。我们先看看你之前的尝试为什么没成功:

  • map concat list无效:因为你的列表里的元素是(a, [b])类型的元组,而concat需要的是[[b]]这种“列表的列表”类型,直接给元组用concat类型完全不匹配,自然没法工作。
  • 你写的map (\t -> (filter (==).first) list ) list报错:首先语法就有问题(应该用fst而不是first,而且函数组合的写法不对),其次逻辑上也没抓住“分组”的核心——你这个写法试图对每个元素过滤整个列表,但既没正确匹配键,也没处理后续的拼接,自然会出错。

接下来给你两种实用的解决方法,选你顺手的用就行:

方法一:用sortOn + groupBy(基础列表操作)

这种方法用Haskell标准库Data.List里的函数,步骤清晰,适合理解分组逻辑:

首先需要导入必要的模块:

import Data.List (sortOn, groupBy)
import Data.Function (on)

然后实现函数:

mergeLists :: Eq a => [(a, [b])] -> [[b]]
mergeLists = map (concat . map snd)  -- 最后一步:把每个组里的列表拼接起来
           . groupBy ((==) `on` fst) -- 第二步:按首元素分组(注意要先排序让同键元素相邻)
           . sortOn fst              -- 第一步:先按首元素排序,确保同键元素挨在一起

测试一下你的输入:

mergeLists [((0,1),[1,2,3]), ((1,2),[7,8,9]), ((0,1),[4,5,6])]
-- 输出:[[1,2,3,4,5,6],[7,8,9]]

方法二:用Data.Map(更简洁的分组方式)

如果你不想手动排序,可以用标准库的Data.Map来直接按键收集列表,这种写法更简洁:

先导入模块:

import qualified Data.Map as Map

实现函数:

mergeLists' :: Ord a => [(a, [b])] -> [[b]]
mergeLists' = Map.elems          -- 提取Map里所有的值(就是拼接好的列表)
            . Map.fromListWith (++) -- 把同键的列表用(++)拼接起来

同样测试你的输入,结果和上面完全一致。这里Map.fromListWith (++)会自动遍历你的列表,遇到相同的键就把对应的列表拼接,最后用Map.elems取出所有结果即可。

两种方法的小区别:

  • 方法一和方法二的结果都会按键的排序顺序输出(因为sortOn和Map都是有序的);
  • 如果你的输入已经是按键排序好的,方法一可以去掉sortOn fst这一步。

内容的提问来源于stack exchange,提问作者Miraj Tzunami

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 07:14:55