2012-10-25 30 views
2

我想一个矩阵的非零元素聚集成一个sequence<(row,column,value)>使用Array2D时可以返回seq吗?

这不起作用

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

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

回答

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

您可以继续坚持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 

如果你原来的意图懒惰不重要,因为上面的代码片段只会热切地给你相同的序列。