如何在Haskell中的Vector的特定范围上映射函数

时间:2015-12-11 23:57:16

标签: haskell vector

我有一个非常大的Vector a,我想在一个小范围内映射一个函数。例如,如果我有一个大小为1000的Vector,我想将函数f映射到索引100-200处的值,然后返回整个更新的Vector。做这个的最好方式是什么。我对其他数据结构持开放态度,但我不想使用可变向量。

编辑: 这是命令式代码中的等价物。

for (int i = startIdx; i < endIdx ; i++){
bigVector[i] = myFunction(bigVector[i]);
}

3 个答案:

答案 0 :(得分:3)

“vector”包的不可变向量实现基本上是一个数组。这意味着对它的任何修改操作都需要遍历整个数组。这种限制并不符合您提到的要求。

由于您说您可以选择不同的数据结构,因此首先需要考虑的是由Array-Mapped Trie算法驱动的数据结构。该算法允许您投影数据结构的片段,连接,删除/获取,追加/前置 - 所有这些都是在常量或对数时间内。它的效率在生产中得到了证明,它推动了Clojure和Scala等语言无处不在的不可变矢量数据结构。

幸运的是,Haskell也有一个实现。它由the "persistent-vector" package呈现,以下是您如何使用它有效地解决问题:

mapOverSlice :: Int -> Int -> (a -> a) -> Vector a -> Vector a
mapOverSlice startIndex length mapper input =
  let
    (split1Heading, split1Trail) =
      splitAt startIndex input
    (split2Heading, split2Trail) =
      splitAt (pred length) split1Trail
    in
      split1Heading <>
      map mapper split2Heading <>
      split2Trail

答案 1 :(得分:0)

这样的东西
maprange :: (a -> a) -> [a] -> Int -> Int -> [a]
maprange f vector skip nb = (take skip vector) ++ (map f (take nb (drop skip vector))) ++ (drop (skip + nb) vector)

然后像

一样使用它
*Main> maprange (\x -> 2*x) [1 .. 10] 3 4
[1,2,3,8,10,12,14,8,9,10]

将前3个元素后的4个元素加倍。

答案 2 :(得分:0)

一种方法是

  • 使用[1 ..]压缩原始矢量以获得带索引
  • 的矢量
  • 映射压缩矢量;如果索引在(跳过,跳过+ nb)之内,则应用f,否则返回原始值

实施非常简单:

maprange :: (a -> a) -> [a] -> Int -> Int -> [a]
maprange f vector skip nb = map (\(idx,v) -> if idx > skip && idx <= skip+nb then f v else v) zipped_vector
     where zipped_vector = zip [1..] vector

复杂性应该是O(n),其中n是原始向量的大小(虽然我不是100%确定zip的复杂性);如果你需要更高效的东西,你应该调查Nikita Volkov在答案中提到的数据结构。