Haskell中从空格分隔整数输入快速构造Vector的最优方法
最快构造Haskell Vector的实现方式
你原代码里用words生成中间列表再转Vector,确实会有额外的内存开销和数据拷贝。要做到无中间列表且最快,核心思路是用高效的输入处理(ByteString)+ 可变Unboxed Vector原地写入,直接把解析出的整数写入Vector,完全跳过列表阶段。
最优实现代码
先导入必要的高效模块:
import qualified Data.Vector.Unboxed as V import qualified Data.Vector.Unboxed.Mutable as MV import qualified Data.ByteString.Char8 as B import Data.Maybe (fromJust)
然后是主逻辑:
main = do n <- readLn :: IO Int -- 读取数字行的ByteString(比String快得多) numLine <- B.hGetLine stdin -- 创建指定长度的可变Unboxed Vector mutableVec <- MV.new n -- 逐解析数字并写入可变Vector let writeToVec idx input | idx >= n = return () | otherwise = case B.readInt input of Nothing -> error "输入格式错误" Just (num, rest) -> do MV.write mutableVec idx num -- 跳过剩余空格,继续解析下一个数字 writeToVec (idx + 1) (B.dropWhile B.isSpace rest) writeToVec 0 numLine -- 冻结可变Vector为不可变的最终Vector finalVec <- V.freeze mutableVec -- 这里可以对finalVec做后续操作 return finalVec
为什么这是最快的?
- ByteString输入处理:
ByteString是连续字节数组,比Haskell默认的String(字符链表)在处理大量输入时快几个数量级,避免了链表的内存碎片化和遍历开销。 - 无中间列表:直接把解析出的整数写入可变Vector,没有生成任何中间列表,减少了一次完整的内存分配和数据拷贝。
- Unboxed Vector:
Unboxed.Vector直接存储原始整数(而非指针),内存密度更高,访问速度更快,比普通Vector更适合数值类型。
关于你考虑的getChar+replicateM方案
这种方式效率极低,不建议用:
getChar是单次IO调用读一个字符,IO操作的系统开销很大,批量读取输入的效率远低于用ByteString一次性读取整行。- 手动逐字符解析整数需要处理空格、正负号、多位数拼接等逻辑,代码繁琐且容易出错,性能完全比不上
ByteString内置的readInt高效解析。
内容的提问来源于stack exchange,提问作者Evg
相关产品推荐
相关产品推荐

