【问题标题】:Haskell create vector with subvectors using indexesHaskell 使用索引创建带有子向量的向量
【发布时间】:2016-05-06 22:11:35
【问题描述】:

我正在尝试创建一个带有子向量的向量,该向量由使用子向量索引的向量从另一个向量中取出的元素组成。 b 中的每个元素对应于a 中的元素在放入c 时应具有的子向量索引。

import Data.Vector
let a = fromList [9,2,3,7,4,1,8,5]
let b = fromList [3,3,2,0,1,1,2,2]
let c = fromList [ a ! k | k <- b ]
Expected c = [[7],[4,1],[3,8,5],[9,2]]

我有点卡住了,收到错误

“无法将预期类型 [Int] 与实际类型 Vector Integer 匹配 在 stmt 列表理解中 k

【问题讨论】:

  • 您在寻找backpermute吗?
  • 不,在反向置换中,索引向量包含应该从a 获取的值的索引,但我的索引向量b 包含应该放置元素的子列表索引。
  • 如果不自己摆弄 ST 和中间可变向量,您肯定不会得到这种行为;我不希望它是内置的。

标签: haskell vector haskell-vector


【解决方案1】:

这不起作用,因为b 是一个向量,而不是一个列表:

k <- b

但是,这可以工作:

[ ... | k <- toList b ]

接下来,ab 的类型为Vector Integer! 运算符采用Int。所以你需要使用fromInteger转换索引:

let c = fromList [ a ! fromInteger k | k <- toList b]

更新

这是一种无需重复遍历数组即可执行转换的方法:

import Data.List

fst3  (b,_,_) = b
third (_,_,a) = a

doit :: Vector Int -> Vector Int -> [[Int]]
doit av bv = [ map third g | g <- groups ]
  where
    triples = zip3 (V.toList bv) [1..] (V.toList av)
    groups = groupBy (\s t -> fst3 s == fst3 t) $ sort triples

这基本上是一个Schwartzian Transform,在排序步骤之后添加了一个 groupBy。三元组的排序是以规范的方式完成的 - 对第一个坐标进行 lex 排序,然后是第二个坐标,然后是第三个坐标。

groups 的表达式还有其他写法:

import Data.Funcition (on)
import GHC.Exts (groupWith)

    ...
    groups = groupBy (on (==) fst3) $ sort triples
    groups = groupWith fst3 triples

请注意,groupBy 要求对三元组进行排序,而 groupWith 则不需要。

【讨论】:

  • 虽然这消除了错误,但结果并不是我想要的。 a 中的每个数字都应添加到 c 中的子向量中,索引在 b 中给出。例如。 a[0] 应该在 c[b[0]] 中。
【解决方案2】:

在 ErikR 的帮助下,我想出了这个:

let c = fromList [fromList [a ! i | i <- [0..Data.Vector.length b-1], (b ! i)==j] | j <- [0..Data.Vector.maximum(b)]]

它有效,但它不漂亮,更好吗?

【讨论】:

  • 好的 - 我现在了解转换。我已经更新了我的答案。
【解决方案3】:

看起来你想要的可能是

accumulate (flip (:)) (replicate n []) (zip b a)

...虽然您将不得不显式计算n,也许是maximum b + 1

【讨论】:

    【解决方案4】:

    对于列表,这似乎是逻辑

    > map (map snd) $ groupBy ((==) `on` fst) $ sortBy (comparing fst) $ zip b a
    
    [[7],[4,1],[3,8,5],[9,2]]
    

    【讨论】: