具有Fortran条件的子集数组?

时间:2015-07-23 16:03:06

标签: fortran

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

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

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

所以B应该是:

B = 15   65   63
    54   32   78

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

感谢您的帮助!

2 个答案:

答案 0 :(得分:2)

你在找这样的东西吗?

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

我假设您的数组为整数。如果编译器将指针实现为返回值,则可以使用指向allocatable的指针。

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

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

答案 1 :(得分:0)

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

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部分为与掩码条件A(:,2)==56匹配的行选择那些索引。

最后,我们使用向量下标来选择具有受限列的合适行。

这样做的唯一真正原因是受益于B的自动分配。这非常有限。

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