2

我想将矩阵的非零元素收集到sequence<(row,column,value)>

这不起作用

let getSparseMatrixCOO matrix =
    seq {
          matrix |> Array2D.iteri (fun row column elem -> 
                                    if elem <> 0.0 then yield (row, column, elem)
                                  )
        }

我必须放弃使用的想法Array2D.iteri吗?

4

2 回答 2

4

您不能yield在这样的 lambda 函数中使用。该yield关键字只能在序列表达式的范围内直接使用(尽管您的尝试具有良好的逻辑)。

我认为最简单的选择是遍历数组的元素并编写如下内容:

let getSparseMatrixCOO matrix =
  seq { for row in 0 .. Array2D.length1 matrix - 1 do
          for column in 0 .. Array2D.length2 matrix - 1 do
            let elem = matrix.[row, column]
            if elem <> 0.0 then yield (row, column, elem) }

Array2D模块不提供很多功能,但可以扩展为包含foldi功能(类似于Array.foldi)。该函数聚合数组的元素并调用您为每个元素指定的函数。然后,您可以选择所需的元素并以您想要的方式聚合它们。

以下使用列表作为状态,并在聚合期间将非零元素附加到列表中:

Array2D.foldi (fun row column elem state -> 
  if elem <> 0.0 then (row, column, elem)::state else state) []

可以像这样实现缺少的Array2D.foldi功能(必须保持简单):

module Array2D =
  let foldi f a matrix = 
    let mutable state = a
    for row in 0 .. Array2D.length1 matrix - 1 do
      for column in 0 .. Array2D.length2 matrix - 1 do
        state <- f row column (matrix.[row, column]) state
    state
于 2012-10-25T17:03:29.687 回答
1

您可以继续坚持Array2D.iteri使用类似的东西

let getSparseMatrixCOO matrix =
    let result = ref List<int*int*float>.Empty
    matrix |> Array2D.iteri(fun i j elem -> if elem <> 0.0 then result := (i,j,elem)::!result)
    !result |> List.rev

如果您的原始意图的懒惰并不重要,因为上面的代码片段会给您相同的顺序,只是急切地。

于 2012-10-25T17:51:16.080 回答