Reputation: 685
I have a 2D array of real numbers, I want to eliminate a row if the first element is less than or equal to zero.
Currently I create another array, fill it with elements corresponding to lines in which the first element is positive and deallocate the original array, but it is inefficient since this should be called many times in my program. Also, it doubles the use of memory.
I have looked into the function PACK, but it seems that it gives as a result only 1D vectors. Is there an analogous function that gives a 2D array as a result?
For example, my array could be something like this:
0 1.2 5.0
-1. 5.0 2.3
2.3 6.7 0.1
3.5 2.9 0.0
And the result should be
2.3 6.7 0.1
3.5 2.9 0.0
Upvotes: 1
Views: 344
Reputation: 60018
This is a sketch how you can keep the data in place and get a pointer to a contiguous n x something array after deleting a "row". However, that only works if you can make the second index to be the row number.
implicit none
integer, allocatable, target :: a(:,:)
integer, pointer :: b(:,:)
integer :: row, rows, iter, n
real :: x
n = 1000
allocate(a(n,n))
a = 0
rows = n
do iter = 1, n/2
call random_number(x)
row = ceiling(x*rows)
a(:,row:rows-1) = a(:,row+1:rows)
rows = rows - 1
b => a(:,1:rows)
print *,size(b,1), size(b,2), is_contiguous(b)
end do
end
If you need the row index to be the first index, it will work as well, but the resulting pointer won't be contiguous.
...
do iter = 1, n/2
call random_number(x)
row = ceiling(x*rows)
a(row:rows-1,:) = a(row+1:rows,:)
rows = rows - 1
b => a(1:rows,:)
print *,size(b,1), size(b,2), is_contiguous(b)
end do
end
If you need a
to be truly reallocated, it won't be possible without a temporary array. If you want to avoid the compiler allocating a new temporary each time, you can use a fixed one manually. The compiler is likely to be re-use the space already being occupied by a
(loc does not change), but it will cost some significant speed time anyway:
implicit none
integer, allocatable :: a(:,:), tmp(:,:)
integer :: row, rows, iter, n
real :: x
n = 1000
allocate(a(n,n), tmp(n,n))
a = 0
tmp = a
rows = n
do iter = 1, n/2
call random_number(x)
row = ceiling(x*rows)
tmp(row:rows-1,:) = a(row+1:rows,:)
rows = rows - 1
a = tmp(1:rows,:)
print *,size(a,1), size(a,2), loc(a)
end do
end
Maybe my code will fail for x = 0, but I ignore this digression for simplicity.
Upvotes: 2