2016-02-05 119 views
2

让我们有一个数组A(:, :)调整大小阵列

Real, Allocatable:: A(:,:), B(:) 
Integer, Allocatable:: rowin(:) 
Integer:: m,j,k, nl 

Allocate(A(max1,max2)) 

几个圈在M,J定义,K

nl = 0 

A(rowin(m)+j,k) = ... 

,现在我要选择子集A(的:, :),使得它们的值是负的,并将它们存储到数组B(:)未知长度的是,即

if(A(rowin(m)+j,k).lt.0.d0) then 
    nl = nl + 1 
    B(nl) = A(rowin(m)+j,k)    
end if 

由于MAX1和MAX2是非常大的数字,我不想分配长度为max1 * max2的B(:),但是正好是A(:, :)包含负值的长度。另外,我不想再次通过m,j和k的复杂循环。 谢谢。

+0

您真的需要Fortran 90或95还是允许Fortran 2003(自动重新分配答案使用来自Fortran 2003,非常有用)。 –

+0

两者都是可能的(首选Fortran 90/95),但需要处理循环和索引,@roygvib提供了他的答案。 – bosona

回答

1

如果B到一些固定尺寸的预分配是不可取的,我们可以模拟动态数组通过使用可分配数组的自动重新分配。在最简单的情况下,我们可以通过添加一个新值来逐个扩展B。例如,假设我们在mj上有双循环,选择符合给定条件的值,并将tho值添加到B。这里,B的大小自动从0,1,2 ......增加。

integer, allocatable :: B(:) 
integer :: m, j 

allocate(B(0)) !! start from an empty array 

do m = 1, 10000 
do j = 1, 10000 

    !! Some condition to add an element, e.g. 
    if (m == j .and. mod(m, 1000) == 0) then 

     !! Add a new element to B. 
     B = [ B, m ] 
    endif 
enddo 
enddo 

print *, "size(B) = ", size(B) 
print *, B(:) 

结果成为

size(B) = 10 
1000 2000 3000 4000 5000 6000 7000 8000 9000 10000 

你的情况,你也许可以添加类似的方式A的期望值,例如

allocate(B(0)) 

do m = 1, ... 
do j = 1, ... 
do k = 1, ... 
    if (A(rowin(m)+j, k) < 0.d0) then !! or any condition 
     B = [ B, A(rowin(m)+j,k) ] 
    end if 
enddo 
enddo 
enddo 

的缺点这种方法的是因为B每次重新分配新元素时效率非常低ent被添加。虽然这对小B没有问题,但对于大B,它可能会成为一个严重的瓶颈。在这种情况下,可以将B的大小增加几何,而不是增加1.例如,下面的代码根据需要将B的大小加倍,以减少重新分配的次数。

integer, allocatable :: B(:) 
integer :: m, j, nl, p 

allocate(B(0)) !! start from an empty array 
nl = 0    !! number of elements found 

do m = 1, 10000 
do j = 1, 10000 

    if (m == j .and. mod(m, 1000) == 0) then 

     nl = nl + 1 

     !! Expand B if the size becomes insufficient. 
     if (size(B) < nl) B = [ B, (0, p=1,nl) ] 

     !! Add a new value. 
     B(nl) = m 
    endif 
enddo 
enddo 

B = B(1 : nl) !! adjust B to the optimal size 

一些更多的注意事项:

  • 如果类似的方法被经常使用,可以很方便地编写一个实用程序像resize()接受一个分配数组作为参数,并改变其大小。如果效率真的很重要,最好在resize()中明确使用allocate()move_alloc()来消除一个临时数组。
  • 上面的代码需要相对较新的编译器支持左侧的可分配数组的自动重新分配。
  • 如果您使用英特尔fortran,则需要添加-assume realloc_lhs选项。如果B的大小可能变得相当大,则还需要-heap-arrays选项。对于gfortran或Oracle fortran,不需要特殊选项。
  • 我们应该不是在左侧附上冒号;即B(:) = [ B, m ]是NG
  • 关于动态数组(例如增长率)的更多细节,请参见Wiki页。
3

这是相当简单:

b = pack(a,a<0.0) 

将包的a负元素向秩1阵列b。最近编译器b将在分配过程中自动分配到正确的大小。

(最新Fortran标准给出了一个非常类似的操作作为pack功能的文档中的示例。)