【问题标题】:How to map a function over a specific range of a Vector in Haskell如何在 Haskell 中的特定向量范围内映射函数
【发布时间】:2015-12-11 23:57:15
【问题描述】:

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

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

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

【问题讨论】:

    标签: haskell vector


    【解决方案1】:

    “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
    

    【讨论】:

    • 嘿尼基塔,感谢您的出色回答。 Clojure 风格的持久向量基本上是我正在寻找的。我想我曾假设 Haskell 的主要 Vector 库等同于 Clojure 的。持久向量比 Data.Sequence 更可取吗?
    • 除非“persistent-vector”的作者在某个地方搞砸了,否则在大多数用例中,由于底层算法,它应该比Data.Sequence更有优势。
    【解决方案2】:

    怎么样

    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 个元素加倍。

    【讨论】:

    • 是连接 (++) O(n+m) 还是在连接向量时进行优化以提高效率?
    【解决方案3】:

    一种方法是

    • 使用 [1..] 压缩您的原始向量以获得带索引的向量
    • 在压缩矢量上映射;如果索引在 (skip, skip+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 的回答中提到的数据结构。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-11-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多