2012-10-25 31 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 

如果你原來的意圖懶惰不重要,因爲上面的代碼片段只會熱切地給你相同的序列。