Reputation: 7938
Suppose I have an array A(n,m). Is it possible to subset that array in Fortran to create a new array? For example,
A = 11 22 43 55
15 56 65 63
54 56 32 78
I want to create an array B with m-1 columns and the rows that satisfies A(:,2) .eq. 56
So B should be:
B = 15 65 63
54 32 78
I don't even know how to start because, for example, the dimension of B should be determined dynamically (I think)
Thanks for the help!
Upvotes: 3
Views: 2200
Reputation: 4656
Are you looking for something like this?
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
That you call like
B = extractB(A)
with B defined like:
integer, dimension(:,:), allocatable :: B
I assumed integer for your arrays. If your compiler implement pointer as return value, you can used pointers in the place of allocatable.
====adding a full program ====
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
Upvotes: 3
Reputation: 32366
A loop is clearly a good way to go, but if you want concise, then
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))])
I should explain this as there are a number of silly things being done here. First note that [..]
is an array constructor, and [(..)]
is an array constructor with an implied-do.
So [(i,i=1,SIZE(A,1))]
creates an array with values 1, ..., N
and [1,(i,i=3,SIZE(A,2))]
an array with values 1, 3, ..., M
. These form the indexes for the rows and columns of A missing out the second column. The PACK
part selects those indexes for rows matching the mask condition A(:,2)==56
.
Finally, we use vector subscripting to select the suitable rows with the restricted columns.
The only real reason for doing this is to benefit from automatic allocation of B
. And that's very marginal.
Don't do this in real code without good documentation.
Upvotes: 2