如何在 Fortran 代码中将二维数组转换为一维数组?
How to convert 2D array to 1D array in Fortran code?
如何将 r(i,j) 转换为一维数组以便轻松对数字进行排序?
program sort
implicit none
character CN*8,O*7
integer j,iconf,nconf
integer i,nbins,t
integer n,nmax,ind,num,b
parameter (n=216)
double precision xbox,rq
parameter (nmax=3091,nconf=1)
double precision atom(nmax),id(nmax),ox(nmax),oy(nmax),oz(nmax)
double precision xij,yij,zij,rij
double precision r(n,n),A(n)
open(unit=10,status='unknown',file='1000.gro')
do iconf= 1,nconf
write(*,*)iconf
read(10,*)
read(10,*)
do i=1,n
read(10,'(A8,A7,1i5,3f8.3)')CN,O,num,ox(i),oy(i),oz(i)
enddo
read(10,*)xbox ! read the xbox for PBC
open(unit=3,file='dist.txt')
do i=1,n
do j=1,n
if(i .ne. j) then
xij=ox(i)-ox(j)
yij=oy(i)-oy(j)
zij=oz(i)-oz(j)
r(i,j)=dsqrt(xij**2 + yij**2 + zij**2)
write(3,'(i3,2x,i3,4x,f17.15)') i,j, r(i,j)
endif
enddo
enddo
enddo
END
我必须计算距离并将其保存在数组中作为 r (i,j)
。我想将 r(i,j)
转换为一维数组,以便我可以轻松地对 r(i,j)
进行排序。
您可以将 r(1,1) 传递给声明参数为一维数组的子例程。这在 Fortran 中是合法的(有一些不适用于您的代码的限制)并使用称为 "sequence association".
的功能
这似乎是为 reshape 函数量身定做的:https://gcc.gnu.org/onlinedocs/gfortran/RESHAPE.html 在这个小例子中,首先使用 reshape 生成二维数组 A,然后再次调用 reshape 生成一维数组 C .
Program reshape_demo
use, intrinsic :: iso_c_binding
implicit none
real(kind=c_float),allocatable :: A(:,:),C(:)
integer(kind=c_int) :: krow
allocate(A(3,3))
A=reshape((/1,2,3,4,5,6,7,8,9/),(/3,3/))
do krow=1,3
write(*,fmt="(1p3e10.3)")A(krow,:)
end do
C=reshape(A,(/9/))
write(*,fmt="(9(1x,f4.1))")C
End Program reshape_demo
之前的两个答案探讨了如何将 rank-2 数组 "convert" 转换为 rank-1 数组的字面问题。他们使用不同的方法:
- 将值复制到新的 rank-1 数组中;
- 在最后的子例程中,有一个与 rank-2 实际参数关联的 rank-1 伪参数。
我们可以扩展这两种方法。
最简单的形式 returns 所需的 rank-1 数组。作为替代方案,我们可以说 [x]
形式的数组构造函数也这样做:
real r1d(6), r2d(3,2)
r2d=5.
r1d = [r2d]
当实参是一个数组虚参时,数组中包含和跟随实参的那些元素是顺序关联的。
使用序列关联,虚拟数组将是假定大小或显式形状。在这种情况下,我们对整个数组感兴趣,我们可以只传递整个数组:
real r2d(3,2)
call sub(r2d)
哪里
subroutine sub(r1d)
real r1d(*) ! or r1d(6), etc.
end subroutine
这里重要的是,对于显式和假定大小的伪参数,等级不需要与实际参数相匹配。
如前所述,第一组方法涉及创建一个新数组。序列关联的使用没有。第三种方法也是可用的:使用指向 rank-2 目标的 rank-1 指针。当然,创建副本也意味着任何更改都不会反映在原始 rank-2 数组中。序列关联和指针将看到传递的更改。
可以在其他问题和答案中找到有关其中任何一项的更多详细信息。
对于排序而言,将 rank-2 数组视为 rank-1 数组是否有意义是一个不同的考虑因素。
现在用FORTRAN的人不多了,问题也不是那么常见了。接受的答案很好,可以形成一个简单的函数,如解决方案 1。但是还有另一种选择,即使用 C_F_POINTER 而不复制源数组(使用大数组可以获得更高的效率)。
解决方案一:
function downsize(A)result(C)
real::A(:,:)
real,allocatable::C(:)
C=reshape(A,[size(A)])
end function downsize
使用函数
real,allocatable::C(:); C=downsize(A);
方案二:
C_F_POINTER 在 ISO Binding 中可以像在 C 中一样传输内存地址。
USE, INTRINSIC :: ISO_C_BINDING
!EDIT...
integer::i,i1d(9)=[(i,i=1,9)]; !reshape((real([(i,i=1,9)])),[9])
integer,dimension(:,:),pointer::p2d
! Here has to be "Deferred-shape" but it only defined a pointer to an array, not an array of pointers as is always misleading...
!EDIT...
real::r2d(3,3)=reshape([(i*1.0,i=1,9)],[3,3])
real, pointer ::pr1d(:)
!Let's Grow the size from I1D to I2D by the pointer pI2D...
call c_f_pointer(c_loc(i1d),pi2d,[3,3])
!The pointer pi2d is a 2d array with the contents of i1d. Note you cannot deallocate the pointer pi2d - any deallocation has to be of pointee i1d.
!Let's Down the size from R2D to R1D by the pointer pR1D ...
call c_f_pointer(c_loc(r2d), pr1d,[size(r2d)])
通过这样做,您将丢失有关距离对应的对的所有信息,但如果它只是您想要的距离,那么我不会得到所有令人费解的答案。为什么不这样做:
[....]
implicit none
real(8), dimension(:), allocatable:: dist_arr
allocate(dist_arr(n**2))
k=0
do i=1,n
do j=1,n
k=k+1
dist_arr(k)=r(i,j)
enddo
enddo
[....]
如何将 r(i,j) 转换为一维数组以便轻松对数字进行排序?
program sort
implicit none
character CN*8,O*7
integer j,iconf,nconf
integer i,nbins,t
integer n,nmax,ind,num,b
parameter (n=216)
double precision xbox,rq
parameter (nmax=3091,nconf=1)
double precision atom(nmax),id(nmax),ox(nmax),oy(nmax),oz(nmax)
double precision xij,yij,zij,rij
double precision r(n,n),A(n)
open(unit=10,status='unknown',file='1000.gro')
do iconf= 1,nconf
write(*,*)iconf
read(10,*)
read(10,*)
do i=1,n
read(10,'(A8,A7,1i5,3f8.3)')CN,O,num,ox(i),oy(i),oz(i)
enddo
read(10,*)xbox ! read the xbox for PBC
open(unit=3,file='dist.txt')
do i=1,n
do j=1,n
if(i .ne. j) then
xij=ox(i)-ox(j)
yij=oy(i)-oy(j)
zij=oz(i)-oz(j)
r(i,j)=dsqrt(xij**2 + yij**2 + zij**2)
write(3,'(i3,2x,i3,4x,f17.15)') i,j, r(i,j)
endif
enddo
enddo
enddo
END
我必须计算距离并将其保存在数组中作为 r (i,j)
。我想将 r(i,j)
转换为一维数组,以便我可以轻松地对 r(i,j)
进行排序。
您可以将 r(1,1) 传递给声明参数为一维数组的子例程。这在 Fortran 中是合法的(有一些不适用于您的代码的限制)并使用称为 "sequence association".
的功能这似乎是为 reshape 函数量身定做的:https://gcc.gnu.org/onlinedocs/gfortran/RESHAPE.html 在这个小例子中,首先使用 reshape 生成二维数组 A,然后再次调用 reshape 生成一维数组 C .
Program reshape_demo
use, intrinsic :: iso_c_binding
implicit none
real(kind=c_float),allocatable :: A(:,:),C(:)
integer(kind=c_int) :: krow
allocate(A(3,3))
A=reshape((/1,2,3,4,5,6,7,8,9/),(/3,3/))
do krow=1,3
write(*,fmt="(1p3e10.3)")A(krow,:)
end do
C=reshape(A,(/9/))
write(*,fmt="(9(1x,f4.1))")C
End Program reshape_demo
之前的两个答案探讨了如何将 rank-2 数组 "convert" 转换为 rank-1 数组的字面问题。他们使用不同的方法:
- 将值复制到新的 rank-1 数组中;
- 在最后的子例程中,有一个与 rank-2 实际参数关联的 rank-1 伪参数。
我们可以扩展这两种方法。
[x]
形式的数组构造函数也这样做:
real r1d(6), r2d(3,2)
r2d=5.
r1d = [r2d]
当实参是一个
使用序列关联,虚拟数组将是假定大小或显式形状。在这种情况下,我们对整个数组感兴趣,我们可以只传递整个数组:
real r2d(3,2)
call sub(r2d)
哪里
subroutine sub(r1d)
real r1d(*) ! or r1d(6), etc.
end subroutine
这里重要的是,对于显式和假定大小的伪参数,等级不需要与实际参数相匹配。
如前所述,第一组方法涉及创建一个新数组。序列关联的使用没有。第三种方法也是可用的:使用指向 rank-2 目标的 rank-1 指针。当然,创建副本也意味着任何更改都不会反映在原始 rank-2 数组中。序列关联和指针将看到传递的更改。
可以在其他问题和答案中找到有关其中任何一项的更多详细信息。
对于排序而言,将 rank-2 数组视为 rank-1 数组是否有意义是一个不同的考虑因素。
现在用FORTRAN的人不多了,问题也不是那么常见了。接受的答案很好,可以形成一个简单的函数,如解决方案 1。但是还有另一种选择,即使用 C_F_POINTER 而不复制源数组(使用大数组可以获得更高的效率)。
解决方案一:
function downsize(A)result(C)
real::A(:,:)
real,allocatable::C(:)
C=reshape(A,[size(A)])
end function downsize
使用函数
real,allocatable::C(:); C=downsize(A);
方案二:
C_F_POINTER 在 ISO Binding 中可以像在 C 中一样传输内存地址。
USE, INTRINSIC :: ISO_C_BINDING
!EDIT...
integer::i,i1d(9)=[(i,i=1,9)]; !reshape((real([(i,i=1,9)])),[9])
integer,dimension(:,:),pointer::p2d
! Here has to be "Deferred-shape" but it only defined a pointer to an array, not an array of pointers as is always misleading...
!EDIT...
real::r2d(3,3)=reshape([(i*1.0,i=1,9)],[3,3])
real, pointer ::pr1d(:)
!Let's Grow the size from I1D to I2D by the pointer pI2D...
call c_f_pointer(c_loc(i1d),pi2d,[3,3])
!The pointer pi2d is a 2d array with the contents of i1d. Note you cannot deallocate the pointer pi2d - any deallocation has to be of pointee i1d.
!Let's Down the size from R2D to R1D by the pointer pR1D ...
call c_f_pointer(c_loc(r2d), pr1d,[size(r2d)])
通过这样做,您将丢失有关距离对应的对的所有信息,但如果它只是您想要的距离,那么我不会得到所有令人费解的答案。为什么不这样做:
[....]
implicit none
real(8), dimension(:), allocatable:: dist_arr
allocate(dist_arr(n**2))
k=0
do i=1,n
do j=1,n
k=k+1
dist_arr(k)=r(i,j)
enddo
enddo
[....]