如何对从大文件中读取的长数据列表(字符串,浮点数等)进行排序 (比如几百万行)使用Data.Vector.Generic.Mutable对象和排序算法 来自Data.Vector.Algorithms?
答案 0 :(得分:16)
以下是一般情况下的操作方法。
首先,你需要一个可变的载体。您可以逐步构建它 你扫描文件;分配一个大约你需要的矢量, 当空间不足时增加尺寸并复制。或者你可以 读取整个文件,计算记录分隔符,并分配 一次性适量的空间。这很容易,但可能不是 在现实生活中可以接受(按需扩展的策略非常好 共同;如果您使用像Perl这样的语言并推送您阅读的行 从一个文件到一个数组的末尾,这就是正在发生的事情。 Perl的 为数组分配一些空间,当你填充它时,它会增加数组 空间量,分配新空间和副本。)
无论如何,我太懒了,所以我只想创建一个向量 其中包含一些随机数字。
我们需要一堆库:
import Control.Monad
import System.Random
import qualified Data.Vector as IV
import qualified Data.Vector.Mutable as MV
import qualified Data.Vector.Generic as V
import qualified Data.Vector.Algorithms.Intro as VA
我们不需要这一切,但最终我们需要它,所以我 以为我会把它弄清楚。
无论如何,我们的可变载体将是一个“正常”的可变载体,
这里MV.MVector
。
可变矢量的想法是你创建它并在一个中修改它
步数。在Haskell中,有几种方法可以实现这一目标
纯粹的调用代码;一个是在ST
monad中完成所有操作。
你的ST动作是创建矢量,修改它并“冻结”它
成为一个不可变的向量。在内部,你正在快速使用
修改-his-memory-location-a-bunch-of-times操作,但是
在外部,你有一些纯粹的东西。 (阅读有关的论文
ST
如果你想要一个关于为什么这是安全的论据。)
处理可变数据的另一种方法是在内部执行此操作
一切,呃,IO
,monad。这就是我们要在这里做的事情
这是最方便的。
(Data.Vector.Mutable
有两种预定义的矢量类型,
IOVector
和STVector
。我们正在使用IOVector
,这就是全部
向量运算到IO
。)
所以像8段前一样,我们将创建一个可变的向量 分类。我们在这里:
randVector :: IO (MV.IOVector Int)
randVector = do
v <- MV.new 10
forM [0..9] $ \x -> do
r <- randomIO :: IO Int
MV.write v x r
return v
这是一个IO动作,返回一个10随机的新可变向量 里面的数字。 (随机数生成也可以方便 升入IO monad,所以我们也这样做了,为了方便起见!它的 就像我们写C一样,但语法更好,类型更安全。)
这实际上是困难的部分。要进行排序,我导入了
Data.Vector.Algorithms.Intro
基本上是就地的
快速排序。一个名为sort
的函数执行实际排序(in
无论哪个monad是可变的载体)。
创建随机可变向量并对其进行排序的操作 看起来像:
sort = VA.sort =<< randVector
现在,要打印出来,我们需要做的就是将矢量“冻结”成
一个不可变的向量,并打印出.toList
。或者你可以
迭代每个元素并打印出来。
以下是我提出的例子:
main = do
v <- randVector
VA.sort v
iv <- V.unsafeFreeze v :: IO (IV.Vector Int)
print . V.toList $ iv
V.unsafeFreeze
来自Data.Vector.Generic
(您如何与之互动
具有相同API的所有矢量类型),V.toList
。
无论如何,值得注意的是,IO纯粹是为了方便起见。
由于您正在从文件数据构建矢量,因此它是合适的。 99%
但是,你应该使用ST
。在你的ST动作中,创建
向量,排序,冻结,并返回冻结版本。
使用STVector
的类似示例:
randVector :: ST s (Vector Int)
randVector = do
vec <- new 10
rand <- newSTRef 17
forM_ [0..9] $ \index -> do
randN <- readSTRef rand
let randN' = (fst . next . mkStdGen) randN
writeSTRef rand randN'
write vec index randN'
unsafeFreeze vec
然后运行:
*Main> runST randVector
fromList [679560,1422110406,306332632,1905242129,692062628,393451229,355476175,1240028023,873588529,1181443777] :: Data.Vector.Vector