这有点复杂;我欢迎任何关于如何提高问题清晰度的意见。
好的,我说我有一个阵列:
real, allocatable :: A(:,:,:)
我想在使用它之前分配它。第三维的大小是否可能取决于第二维的大小?
E.g。
do i=1,n
allocate(A(3,i,i**2))
end do
显然上述方法不起作用。我想最终得到一个带有形状的数组(或一组数组)
(3,1,1), (3,2,4), (3,3,9), ... (3, n, n^2)
其中第三维的大小是第二维的大小的平方。
我对依赖维度大小的规则有点复杂,但如果可以进行平方,我可以完成其余的工作。
这可能吗?如果是这样,我如何在Fortran中实现它?
shape(A)
会返回什么?那会很有趣。
我的另一种选择是分配所需的最大尺寸,并注意只在计算中使用某些元素,即
allocate(A(3,n,n**2))
即使我现在并不努力记忆,我也希望有良好的编程习惯。无论如何,这是一个有趣的问题。
谢谢。
编辑:
维度的大小取决于另一维度中元素的值怎么样?
在下面的答案中,两个维度中数组的大小取决于B的索引。我喜欢
的内容。type myarray
real :: coord(3)
integer,allocatable :: lev(:)
integer, allocatable :: cell(:)
endtype myarray
type(myarray), allocatable :: data
allocate(data(m))
allocate(data%lev(n))
forall (j=1:n) !simple now, for argument's sake
lev(j)=j
endforall
! I was thinking of using a FORALL loop here, but the errors returned
! suggested that the compiler (gfortran) didn't expect IF blocks and ALLOCATE
! statements in a FORALL block
do i=1,m
do j=1,n
allocate(data(i)%cell(lev(j)**2))
enddo
enddo
你理解我的意思?但是当程序试图分配已经分配的变量时,程序就会失败,例如:当i=1
分配data(1)%cell(1)
,然后尝试分配data(1)%cell(2)
时......呃哦。我想要的是:
每个data(i)
都有一个数组lev(j)
,j
从1到n运行,每个lev(j)
值都有一个cell
大小lev
^ 2。请注意,这些cell
对于每个data(i)
和每个lev
都是唯一的,并且该特定cell
的大小取决于相应的lev
值,也可能是相应的data(i)
。
我是否必须在派生类型中使用派生类型?
答案 0 :(得分:9)
是的,您可以使用派生类型来完成此任务:
TYPE array
REAL,DIMENSION(:,:,:),ALLOCATABLE :: A
ENDTYPE array
INTEGER :: i
INTEGER,PARAMETER :: n=10
TYPE(array),DIMENSION(:),ALLOCATABLE :: B
ALLOCATE(B(n))
DO i=1,n
ALLOCATE(B(i)%A(3,i,i*i))
WRITE(*,*)SHAPE(B(i)%A)
ENDDO
END
这种方法允许数组B的每个元素都是不同形状的多维数组。
程序的输出符合预期:
3 1 1
3 2 4
3 3 9
3 4 16
3 5 25
3 6 36
3 7 49
3 8 64
3 9 81
3 10 100
编辑:进一步回答OP的编辑问题。是的,看起来你需要做这样的事情,使用嵌套派生类型(比较你的代码示例来弄清楚你做错了什么):
integer,parameter :: m=3,n=5
type cellarray
integer,dimension(:),allocatable :: c
endtype cellarray
type myarray
integer,allocatable :: lev(:)
type(cellarray),dimension(:),allocatable :: cell
endtype myarray
type(myarray),dimension(:),allocatable :: B
allocate(B(m))
! Allocate and assign lev and cell:
do i=1,m
allocate(B(i)%lev(n))
allocate(B(i)%cell(n))
do j=1,n
B(i)%lev(j)=j
enddo
enddo
! Based on value of lev, allocate B%cell%c:
do i=1,m
do j=1,n
allocate(B(i)%cell(j)%c(B(i)%lev(j)**2))
enddo
enddo
! Print out to check that it works:
do j=1,n
write(*,*)j,B(1)%lev(j),SIZE(B(1)%cell(j)%c)
enddo
end
用gfortran 4.6.2尝试过这个。它产生预期的输出:
1 1 1
2 2 4
3 3 9
4 4 16
5 5 25
答案 1 :(得分:1)
我认为你可以通过分配/解除分配数组
来做到这一点Program test
Implicit none
Real, dimension(:,:,:), allocatable :: A
Integer :: i,N
Write(*,*)"Enter N"; Read(*,*)N
Do i = 1, N
if(Allocated(A)) then
deallocate(A);Allocate(A(i,i,i*i))
else
allocate(A(i,i,i*i))
end if
Write(*,*)Shape(A)
End do
end program test
使用gfortran编译程序给出:
Enter N
5
1 1 1
2 2 4
3 3 9
4 4 16
5 5 25