如何在 Fortran 90 中向动态数组添加新元素
How to add new element to dynamical array in Fortran 90
我需要在 Fortran 90 中使用动态数组来应对最初无法预测数组的确切大小的情况。所以我写了一段代码,每次将新元素添加到数组末尾时都应该扩展可分配数组:
subroutine DArray()
double precision, dimension(:), allocatable :: list
allocate(list(1))
list(1) = 1.1
call AddToList(list, 2.2)
call AddToList(list, 3.2)
call AddToList(list, 4.2)
call AddToList(list, 5.2)
print *, list(1)
print *, list(2)
print *, list(3)
print *, list(4)
print *, list(5)
end
subroutine AddToList(list, element)
double precision :: element
double precision, dimension(:), allocatable :: list
double precision, dimension(:), allocatable :: clist
if(allocated(list)) then
isize = size(list)
allocate(clist(isize+1))
do i=1,isize
clist(i) = list(i)
end do
clist(i+1) = element
deallocate(list)
allocate(list(isize+1))
do i=1,isize+1
list(i) = clist(i)
end do
deallocate(clist)
end if
end
所以有人看到我是否遗漏了什么吗?
由 francescalus 解决。
双精度动态数组的工作代码是:
module DynamicalArrays
contains
subroutine AddToList(list, element)
IMPLICIT NONE
integer :: i, isize
double precision, intent(in) :: element
double precision, dimension(:), allocatable, intent(inout) :: list
double precision, dimension(:), allocatable :: clist
if(allocated(list)) then
isize = size(list)
allocate(clist(isize+1))
do i=1,isize
clist(i) = list(i)
end do
clist(isize+1) = element
deallocate(list)
call move_alloc(clist, list)
else
allocate(list(1))
list(1) = element
end if
end subroutine AddToList
end module DynamicalArrays
可从中填充数组的演示子例程为:
subroutine UserDArrayTest()
use DynamicalArrays
integer :: i
double precision, dimension(:), allocatable :: list
double precision :: temp
temp = 0.1
do i=1,10
temp = temp+1
call AddToList(list, temp)
end do
do i=1,10
print *, i, list(i)
end do
end
请注意,最好将模块代码保存在单独的文件中,但我也发现,当模块代码位于主程序和子程序代码之上时,它也可以工作。
我怀疑,看着一个人工制品,你注意到了这个问题 - 但很快就继续了。
可疑行,对我来说是:
allocate(clist(isize+2))
为什么不是新尺寸 isize+1
?我猜你试过了,但是程序失败了。
了解程序失败(可能崩溃)的原因是您无法获得正确结果的关键。仔细查看循环(为清楚起见,删除了打印语句)。
do i=1,isize
clist(i) = list(i)
end do
clist(i+1) = element
你想说"copy all elements from list to clist, then append element"。哪个是正确的。不过
do i=1,isize
clist(i) = list(i)
end do
! Here, i=isize+1
clist(i+1) = element
! Which means
! clist(isize+2) = element.
总而言之,在循环之后,循环索引变量没有它在最后一次迭代中的值。
我知道这个问题很老了,但我最近不得不建立这样一个子程序,我发现,从Fortran2003开始,有一个漂亮的衬里:
SUBROUTINE append_int(vec, val)
!***********************************************************************
!> \brief Appends val in vec if not already present
!> \date 05 2020
!***********************************************************************
INTEGER, DIMENSION(:), ALLOCATABLE, INTENT(INOUT) :: vec
INTEGER, INTENT(IN) :: val
! Remove this test if you don't mind not having unique values
IF (.NOT. ANY(vec .EQ. val)) THEN
vec = [vec, val]
END IF
END SUBROUTINE
您的数组将自动重新分配到合适的大小。
另外,您可以为 Reals 生成等效例程,用于将一个数组附加到另一个……然后将它们全部包装在一个接口中,这样无论您的数据类型如何,您始终可以调用相同的子例程。
我需要在 Fortran 90 中使用动态数组来应对最初无法预测数组的确切大小的情况。所以我写了一段代码,每次将新元素添加到数组末尾时都应该扩展可分配数组:
subroutine DArray()
double precision, dimension(:), allocatable :: list
allocate(list(1))
list(1) = 1.1
call AddToList(list, 2.2)
call AddToList(list, 3.2)
call AddToList(list, 4.2)
call AddToList(list, 5.2)
print *, list(1)
print *, list(2)
print *, list(3)
print *, list(4)
print *, list(5)
end
subroutine AddToList(list, element)
double precision :: element
double precision, dimension(:), allocatable :: list
double precision, dimension(:), allocatable :: clist
if(allocated(list)) then
isize = size(list)
allocate(clist(isize+1))
do i=1,isize
clist(i) = list(i)
end do
clist(i+1) = element
deallocate(list)
allocate(list(isize+1))
do i=1,isize+1
list(i) = clist(i)
end do
deallocate(clist)
end if
end
所以有人看到我是否遗漏了什么吗?
由 francescalus 解决。
双精度动态数组的工作代码是:
module DynamicalArrays
contains
subroutine AddToList(list, element)
IMPLICIT NONE
integer :: i, isize
double precision, intent(in) :: element
double precision, dimension(:), allocatable, intent(inout) :: list
double precision, dimension(:), allocatable :: clist
if(allocated(list)) then
isize = size(list)
allocate(clist(isize+1))
do i=1,isize
clist(i) = list(i)
end do
clist(isize+1) = element
deallocate(list)
call move_alloc(clist, list)
else
allocate(list(1))
list(1) = element
end if
end subroutine AddToList
end module DynamicalArrays
可从中填充数组的演示子例程为:
subroutine UserDArrayTest()
use DynamicalArrays
integer :: i
double precision, dimension(:), allocatable :: list
double precision :: temp
temp = 0.1
do i=1,10
temp = temp+1
call AddToList(list, temp)
end do
do i=1,10
print *, i, list(i)
end do
end
请注意,最好将模块代码保存在单独的文件中,但我也发现,当模块代码位于主程序和子程序代码之上时,它也可以工作。
我怀疑,看着一个人工制品,你注意到了这个问题 - 但很快就继续了。
可疑行,对我来说是:
allocate(clist(isize+2))
为什么不是新尺寸 isize+1
?我猜你试过了,但是程序失败了。
了解程序失败(可能崩溃)的原因是您无法获得正确结果的关键。仔细查看循环(为清楚起见,删除了打印语句)。
do i=1,isize
clist(i) = list(i)
end do
clist(i+1) = element
你想说"copy all elements from list to clist, then append element"。哪个是正确的。不过
do i=1,isize
clist(i) = list(i)
end do
! Here, i=isize+1
clist(i+1) = element
! Which means
! clist(isize+2) = element.
总而言之,在循环之后,循环索引变量没有它在最后一次迭代中的值。
我知道这个问题很老了,但我最近不得不建立这样一个子程序,我发现,从Fortran2003开始,有一个漂亮的衬里:
SUBROUTINE append_int(vec, val)
!***********************************************************************
!> \brief Appends val in vec if not already present
!> \date 05 2020
!***********************************************************************
INTEGER, DIMENSION(:), ALLOCATABLE, INTENT(INOUT) :: vec
INTEGER, INTENT(IN) :: val
! Remove this test if you don't mind not having unique values
IF (.NOT. ANY(vec .EQ. val)) THEN
vec = [vec, val]
END IF
END SUBROUTINE
您的数组将自动重新分配到合适的大小。 另外,您可以为 Reals 生成等效例程,用于将一个数组附加到另一个……然后将它们全部包装在一个接口中,这样无论您的数据类型如何,您始终可以调用相同的子例程。