Если предварительно выделение B
некоторого фиксированного размера не желательно, мы можем подражать динамический массив используя автоматическое перераспределение выделенного массива. В простейшем случае мы можем развернуть B
, добавив новое значение. Например, предположим, что у нас есть двойные петли над m
и j
, выберите значения, которые соответствуют заданному условию, и добавьте значения 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
перераспределяется каждый раз, когда новый элемент добавляется. Хотя это не проблема для небольших 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()
, который принимает размещаемый массив в качестве аргумента и изменяет его размер.Если эффективность действительно имеет значение, может быть лучше использовать allocate()
и move_alloc()
явно в resize()
для устранения одного временного массива.
- Приведенный выше код требует относительно новых компиляторов, который поддерживает автоматическое перераспределение распределяемых массивов в левой части.
- Если вы используете Intel fortran, необходимо добавить опцию
-assume realloc_lhs
. Если размер B
может стать довольно большим, вам также понадобится -heap-arrays
. Для gforran или fortran Oracle не требуются специальные параметры.
- Мы должны не установить двоеточие в левой части; то есть
B(:) = [ B, m ]
является NG
- Подробнее о динамических массивах (например, скорости роста) см. на странице Wiki.
Действительно ли вам нужен Fortran 90 или 95 или вы разрешаете Fortran 2003 (автоматическое перераспределение ответов используется с Fortran 2003 и очень полезно). –
Возможно и то, и другое (желательно Fortran 90/95), но нужно иметь дело с циклами и индексами, как @roygvib представил свой ответ. – bosona