使用Array2D时是否可以返回seq?

时间:2012-10-25 16:43:17

标签: f#

我想将矩阵的非零元素收集到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

的想法

2 个答案:

答案 0 :(得分:4)

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

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

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

答案 1 :(得分: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

如果您的原始意图的懒惰无关紧要,因为上面的代码段会给您相同的序列,只是热切地。