【问题标题】:How can you sort rows in an array based on ascending column values?如何根据升序列值对数组中的行进行排序?
【发布时间】:2018-03-06 23:26:48
【问题描述】:

例如,如果我有以下二维数组:

2   1   4
1   2   3
2   1   2

并且想按每一行排序,我如何使用列值进行升序?在这种情况下,我可以对数组中的第一列进行排序,得到

1 2 3
2 1 4
2 1 2 

有了这个例子,我的最终结果应该是这样的:

1 2 3
2 1 2
2 1 4

首先我想查看第一列,然后对行进行排序。由于两行以 2 开头,我想查看第二列并进行排序。如果这些数字仍然相同,我想查看下一列,依此类推。我该怎么做?

【问题讨论】:

  • 最好或什至期望至少提供一些代码。现在你很幸运,你的问题得到了很好的接受,但这并不总是发生。许多人会否决您的问题,而不是为您编写整个代码。见How to Ask

标签: arrays sorting multidimensional-array fortran row


【解决方案1】:

你需要的是两个不同的程序:

一个将两行相互比较并决定哪一个应该先行,另一个实际进行排序。

这是一个使用了不好实现的冒泡排序的版本:

program sort

    implicit none
    integer, parameter :: num_rows = 3
    integer, parameter :: num_cols = 3
    character(len=*), parameter :: fmt = '(3I4)'
    integer :: a(num_cols,num_rows)

    a = reshape([2, 1, 4, 1, 2, 3, 2, 1, 2], [3, 3])

    call sortrow(a)

    print fmt, a

contains

    subroutine sortrow(a)
        implicit none
        integer, intent(inout) :: a(num_cols, num_rows)
        integer :: i, j
        integer :: tmp(num_cols)
        do i = 1, num_rows
            do j = i+1, num_rows
                if (islarger(a(:,i), a(:,j))) then
                    tmp(:) = a(:, i)
                    a(:, i) = a(:, j)
                    a(:, j) = tmp(:)
                end if
            end do
        end do
    end subroutine sortrow

    function islarger(a, b)
        implicit none
        integer, intent(in) :: a(num_cols), b(num_cols)
        logical :: islarger
        integer :: i
        do i = 1, num_cols
            if (a(i) > b(i)) then
                islarger = .TRUE.
                return
            end if
            if (b(i) > a(i)) then
                islarger = .FALSE.
                return
            end if
        end do
        islarger = .FALSE.
        return
    end function islarger

end program sort

或者,您可以编写一个函数,将行映射到单个整数值,这样如果行 n 必须在 m 之后,那么这个值n 大于 m

例如,如果所有值都是单个数字(0 到 9),那么您可以将 [2, 1, 4] 转换为 214,这样会更容易排序。

【讨论】:

    【解决方案2】:

    我尝试了编写standard C library subroutine qsort 接口的惰性方法。为了避免全局数据,我将比较函数作为调用qsort 并保存要排序的数组的子例程的内部函数。中间子例程分配qsort 实际排序的索引数组,然后索引数组用于拉直输入数组。以下是它的工作原理:

    module sortmod
       use ISO_C_BINDING
       implicit none
       interface
          subroutine qsort(base,nitems,size,compar) bind(C,name='qsort')
             import
             implicit none
             type(C_PTR), value :: base
             integer(C_SIZE_T), value :: nitems
             integer(C_SIZE_T), value :: size
             interface
                function compar(x,y) bind(C)
                   import
                   implicit none
                   integer(C_INT) compar
                   type(C_PTR),value :: x
                   type(C_PTR),value :: y
                end function compar
             end interface
          end subroutine qsort
       end interface
       contains
          recursive subroutine startsort(array)
             integer(C_INT) array(:,:)
             integer(C_INT), allocatable, target :: indices(:)
             integer i
             indices = [(i,i=1,size(array,1))]
             call qsort(C_LOC(indices),size(indices,1,kind=C_SIZE_T),C_SIZEOF(indices(1)),callback)
             array = array(indices,:)
             contains
                function callback(x,y) bind(C)
                   integer(C_INT) callback
                   type(C_PTR), value :: x, y
                   integer(C_INT), pointer :: ix,iy
                   integer j
                   call C_F_POINTER(x,ix)
                   call C_F_POINTER(y,iy)
                   callback = 0
                   do j = 1, size(array,2)
                      callback = array(ix,j) - array(iy,j)
                      if(callback /= 0) return
                   end do
                end function callback
          end subroutine startsort
    end module sortmod
    
    program testsort
       use sortmod
       implicit none
       integer(C_INT), allocatable :: array(:,:)
       character(20) fmt
       array = reshape([2, 1, 4, &
                        1, 2, 3, &
                        2, 1, 2], &
                        [3, 3], order = [2, 1])
       call startsort(array)
       write(fmt,'(*(g0))') '(',size(array,2),'i3)'
       write(*,fmt) transpose(array)
    end program testsort
    

    使用 gfortran 输出:

      1  2  3
      2  1  2
      2  1  4
    

    【讨论】:

    • 您确定要在compar 接口中使用Fortran 接口qsort 吗?我不认为它是严格正确的,互操作性得不到保证。我只是使用c_funptrbitbucket.org/LadaF/elmm/src/…
    • @VladimirF 我阅读了标准的第 18.3.7 节,'如果......(5)任何没有 VALUE 属性的虚拟参数对应于形式指针类型的原型参数和 * 虚拟参数可与形式参数的引用类型(ISO/IEC 9899:2011、6.25、7.19 和 7.20.1)的实体互操作......' 和除了如果它不能工作,为什么标准会让你将过程作为实际参数传递?在这方面它禁止其他不可能的语法。
    • 好吧,编译器允许各种不严格符合的东西,如果它们不破坏约束的话。感谢您的参考。
    • @VladimirF 我还讨论过是否将FUNCTION compar 的虚拟参数xy 声明为INTEGER(C_INT),而不是按值。这将是更自然的 Fortran 接口,但我最终没有这样做,因为我认为编译器可能会优化对 C_F_POINTER 的调用,而且我不想通过解释你可能不得不混淆这个问题为qsort()的每个上下文写出不同的接口体。
    猜你喜欢
    • 2015-11-08
    • 2019-09-09
    • 1970-01-01
    • 1970-01-01
    • 2019-12-19
    • 1970-01-01
    • 2021-06-24
    • 2012-08-04
    • 1970-01-01
    相关资源
    最近更新 更多