F# - 对包含元组的矩阵进行排序

时间:2011-09-02 14:18:26

标签: sorting f# matrix tuples

我找不到对以下元组矩阵的列中包含的值进行排序的方法:

Matrix<float * float> =
  matrix [[(1.0, 145.0); (1.0, 45.0); (1.0, 130.0); (1.0, 30.0); (1.0, 130.0)]
          [(2.0, 45.0); (2.0, 45.0); (2.0, 30.0); (2.0, 30.0); (2.0, 30.0)]
          [(3.0, 130.0); (3.0, 30.0); (3.0, 145.0); (3.0, 45.0); (3.0, 130.0)]
          [(4.0, 30.0); (4.0, 30.0); (4.0, 45.0); (4.0, 45.0); (4.0, 30.0)]
          [(5.0, 130.0); (5.0, 30.0); (5.0, 130.0); (5.0, 30.0); (5.0, 145.0)]]

我想根据元组的第二个元素每列进行排序。例如,答案是:

   matrix [[(1.0, 145.0); (1.0, 45.0); (3.0, 145.0); (3.0, 45.0); (5.0, 145.0)]
          [(3.0, 130.0); (2.0, 45.0); (1.0, 130.0); (4.0, 45.0); (1.0, 130.0)]
          [(5.0, 130.0); (3.0, 30.0); (5.0, 130.0); (1.0, 30.0); (3.0, 130.0)]
          [(2.0, 45.0); (4.0, 30.0); (4.0, 45.0); (2.0, 30.0); (2.0, 30.0)]
          [(4.0, 30.0); (5.0, 30.0); (2.0, 30.0); (5.0, 30.0); (4.0, 30.0)]]

提前谢谢!

3 个答案:

答案 0 :(得分:2)

以下是这样一个功能:

let sortByCol f (m:Matrix<'T>) = 
    let n = m.Transpose
    [for i = 0 to n.NumRows-1 do 
        yield [for j in n.Row(i) -> j] 
              |> List.sortBy f ]
    |> Matrix.Generic.ofList
    |> Matrix.Generic.transpose

特别针对这个问题使用:

matrix |> sortByCol (fun (_,b) -> -b)

更新:按col函数进行排序。

答案 1 :(得分:2)

根据我的经验,在使用数组(2D和/或矩阵)时,我发现在内部使用数组通常是最快的方法。

例如,以可变的方式结合Daniel和Ankur的方法:

let mutableSortByCol f (m:Matrix<'T>) =
    let columns = [| for c in 0 .. m.NumCols - 1 -> 
                         m.Column c |> Vector.Generic.toArray |]

    for c in 0 .. m.NumCols - 1 do 
        columns.[c] |> Array.sortInPlaceBy f

    Matrix.Generic.init (m.NumRows) (m.NumCols) (fun r c -> columns.[c].[r])

我将矩阵转换为列数组('a [] [],而不是'a [,]),并在每列上执行就地排序。之后,我用一个新的矩阵填充了排序结果。请注意,原始矩阵保持不变:列数组中填充了列向量的副本(Vector.toArray创建了一个新数组)。

这种方法更快,因为它不需要转置,对列进行排序,并且不需要通过保持所有面向数组的方式来转换到中间列表结构。我怀疑如果Matrix模块支持转换为'a [] []的转换,它可能会更快,尽管它可能不适合矩阵。

另外,如果您不知道:您可以使用F#的元组结构比较来按第二个元素降序排序,第一个元素升序:

示例:

> mutableSortByCol (fun (a,b) -> (-b,a)) M;;
val it : Matrix<float * float> =
  matrix [[(1.0, 145.0); (1.0, 45.0); (3.0, 145.0); (3.0, 45.0); (5.0, 145.0)]
          [(3.0, 130.0); (2.0, 45.0); (1.0, 130.0); (4.0, 45.0); (1.0, 130.0)]
          [(5.0, 130.0); (3.0, 30.0); (5.0, 130.0); (1.0, 30.0); (3.0, 130.0)]
          [(2.0, 45.0); (4.0, 30.0); (4.0, 45.0); (2.0, 30.0); (2.0, 30.0)]
          [(4.0, 30.0); (5.0, 30.0); (2.0, 30.0); (5.0, 30.0); (4.0, 30.0)]]

答案 2 :(得分:1)

我之前从未使用Matrix因此可能有更好的方法,但这似乎有效:

let sortMatrix (m:Matrix<_>) =
  seq {
    for c in 0 .. (m.NumCols - 1) do
      let arr = [| for r in 0 .. (m.NumRows - 1) -> m.[r, c] |]
      arr |> Array.sortInPlaceBy (fun (_, b) -> -b : float) //(snd >> (~-))
      yield arr
  }
  |> Matrix.Generic.ofSeq 
  |> Matrix.Generic.transpose