如何使用Data.Vector.Generic.Mutable进行排序?

时间:2010-09-07 02:13:56

标签: arrays sorting haskell vector

如何对从大文件中读取的长数据列表(字符串,浮点数等)进行排序 (比如几百万行)使用Data.Vector.Generic.Mutable对象和排序算法 来自Data.Vector.Algorithms?

1 个答案:

答案 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有两种预定义的矢量类型, IOVectorSTVector。我们正在使用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