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

发布于 2024-12-02 19:23:15 字数 984 浏览 1 评论 0原文

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

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)]]

提前谢谢您!

I do not find a way to sort the values included in the columns of the following matrix of 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)]]

I would like to sort each column depending on the second element of the tuple. For example here the answer would be :

   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)]]

Thank you in advance !

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

宣告ˉ结束 2024-12-09 19:23:15

根据我的经验,在使用数组(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)]]

In my experience, when working with arrays (2D and/or matrix) I found that working with arrays internally is often the fastest way to go.

For example, combining Daniel's and Ankur's approaches in a mutable way:

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])

I converted the matrix to an array of columns ('a[][], not 'a[,]), and performed an in-place sort on each column. After that, I filled a new matrix with the sorted result. Note that the original matrix remains unmodified: the columns array is populated with copies of the column vectors (Vector.toArray creates a new array).

This approach is faster because it needs no transposes, sorts columns in place, and needs no conversion to and from intermediate list structures by keeping everything array-oriented. I suspect it could be made even faster if the Matrix module supported conversion to/from 'a[][] as well, although it's perhaps not really suited for matrices.

Also, in case you didn't know: you can make use of F#'s structural comparison of tuples to sort by second element descending, first element ascending:

Example:

> 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)]]
梦里的微风 2024-12-09 19:23:15

下面是这样一个函数:

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 排序的函数变得通用。

Below is such a function:

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

Usage as particular to this question:

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

UPDATED: To make the sort by col function generic.

第几種人 2024-12-09 19:23:15

我以前从未使用过 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

I've never used Matrix before so there might be a better way, but this seems to work:

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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文