Fortran 给定条件的子集数组?

subset array with Fortran given a condition?

假设我有一个数组 A(n,m)。是否可以在 Fortran 中对该数组进行子集化以创建一个新数组?例如,

A = 11   22   43   55
    15   56   65   63
    54   56   32   78

我想创建一个包含 m-1 列和满足 A(:,2) .eq 的行的数组 B。 56

所以 B 应该是:

B = 15   65   63
    54   32   78

我什至不知道如何开始,因为例如B的维度应该是动态确定的(我认为)

感谢您的帮助!

您在找这样的东西吗?

function extractB(A) result(B)
    integer, dimension(:,:), intent(in) :: A
    integer, dimension(:,:), pointer :: B
    integer :: nrowB, i, pos

    nrowB = count( A(:,2)==56)
    allocate( B(nrowB, size(A,2)-1 ) )
    pos = 1
    do i = 1, size(A,1)
        if(A(i,2)==56)then
            B(pos,1) = A(i,1)
            B(pos,2:) = A(i,3:)
            pos = pos+1
        end if
    end do
end function extractB

你这样称呼

B = extractB(A)

B 定义如下:

integer, dimension(:,:), allocatable :: B

我假设你的数组是整数。如果您的编译器将指针实现为 return 值,则可以在可分配的位置使用指针。

====添加一个完整的程序====

module extract
contains

    subroutine testExtract(A, B)
        double precision, dimension(:,:), intent(in)           :: A
        double precision, dimension(:,:), intent(out), allocatable :: B

        B = extractB(A)


    end subroutine testExtract


    function extractB(A) result(B)
        double precision, dimension(:,:), intent(in) :: A
        double precision, dimension(:,:), allocatable :: B
        integer :: nrowB, i, pos

        nrowB = count( A(:,2)==56)
        allocate( B(nrowB, size(A,2)-1 ) )
        pos = 1
        do i = 1, size(A,1)
            if(A(i,2)==56)then
                B(pos,1) = A(i,1)
                B(pos,2:) = A(i,3:)
                pos = pos+1
            end if
        end do
    end function extractB
end module extract

program test
    use extract
    integer, parameter :: n = 3
    integer, parameter :: m = 4
    double precision, dimension(3,4) :: A
    double precision, dimension(:,:), allocatable :: B


    A(1,:) = [11,   22,   43,   55]
    A(2,:) = [15,   56,   65,   63]
    A(3,:) = [54,   56,   32,   78]

    print*, 'A :'
    print*, int(A)

    !B = extractB(A)
    call testExtract(A, B)
    print*, 'B'
    print*, int(B)

end program

循环显然是个好方法,但如果你想要简洁,那么

integer, dimension(N,M) :: A
integer, allocatable :: B(:,:)
integer i

A = ...

B = A(PACK([(i,i=1,SIZE(A,1))],A(:,2)==56),[1,(i,i=3,SIZE(A,2))])

我应该解释一下,因为这里有很多愚蠢的事情。首先注意 [..] 是一个数组构造函数,而 [(..)] 是一个带有隐式 do 的数组构造函数。

所以 [(i,i=1,SIZE(A,1))] 创建一个数组 1, ..., N[1,(i,i=3,SIZE(A,2))] 一个数组 1, 3, ..., M。这些构成了 A 中缺少第二列的行和列的索引。 PACK 部分 select 是匹配掩码条件 A(:,2)==56.

的那些行的索引

最后,我们使用矢量下标 select 具有受限列的合适行。

这样做的唯一真正原因是受益于 B 的自动分配。那是非常微不足道的。

如果没有良好的文档,请不要在实际代码中执行此操作。