From: bing999 on
Hi,

i am a beginner in F90 and I do not know how to select some array
elements according to its values.

That is to say what is the equivalent of the "where" function (in IDL)
in fortran.

a = [ 2,5,9,-7,4,-8]
b = [ 100,200,300,400,500,600]

I want to know the index of the positive values of the array a ( here
the index are 1, 2, 3 and 5) and pass them to my b array to keep only
the b items for which a is positive...I would do

b = b(where(a ge 0)) in IDL and it would give: b = 100, 200, 300, 500

but no idea how to do it in fortran...
Does anyone know??

Thanks
From: Arjen Markus on
On 26 mrt, 15:53, bing999 <thibaultga...(a)gmail.com> wrote:
> Hi,
>
> i am a beginner in F90 and I do not know how to select some array
> elements according to its values.
>
> That is to say what is the equivalent of the "where" function (in IDL)
> in fortran.
>
> a = [ 2,5,9,-7,4,-8]
> b = [ 100,200,300,400,500,600]
>
> I want to know the index of the positive values of the array a ( here
> the index are 1, 2, 3 and 5) and pass them to my b array to keep only
> the b items for which a is positive...I would do
>
> b = b(where(a ge 0)) in IDL  and it would give: b = 100, 200, 300, 500
>
> but no idea how to do it in fortran...
> Does anyone know??
>
> Thanks

You can do that with the pack() function:

pack( b, a >= 0 )

but there is a caveat:
The result is an array whose length you do not know in advance. That
means that you can not simply say:

b = pack( b, a >= 0 )

The array b is not automatically resized (in Fortran 2003 that does
happen)

What you can do instead is pass the result to a subroutine:

integer, dimension(:), allocatable :: b

call resize( b, pack( b, a >= 0 ) )
....
subroutine resize( b, fill )
integer, dimension(:), allocatable, intent(inout) :: b
integer, dimension(:), intent(in) :: fill

deallocate( b )
allocate( b(1:size(fill) )
b = fill

end subroutine

Or you can simply pass the result of pack() to a subroutine and
work with the dummy argument:

call examine( pack( b, a >= 0 ) )

subroutine examine( r )
integer, dimension(:) :: r ! Ordinary array, but you should not
change the
! elements' values
...
end subroutine

Yet another way is:

b = (/ pack( b, a>= 0 ), pack( b, a < 0 ) /)

With the array constructor (/ .. /) you simply shift the negative
elements to the back. The contructed array on the right has the same
size as b (because of the complementary conditions)

A lengthy expose, but I hope this helps you understand the
possibilities.

Regards,

Arjen
From: Tom Micevski on
bing999 wrote:
> Hi,
>
> i am a beginner in F90 and I do not know how to select some array
> elements according to its values.
>
> That is to say what is the equivalent of the "where" function (in IDL)
> in fortran.
>
> a = [ 2,5,9,-7,4,-8]
> b = [ 100,200,300,400,500,600]
>
> I want to know the index of the positive values of the array a ( here
> the index are 1, 2, 3 and 5) and pass them to my b array to keep only
> the b items for which a is positive...I would do
>
> b = b(where(a ge 0)) in IDL and it would give: b = 100, 200, 300, 500
>
> but no idea how to do it in fortran...
> Does anyone know??

seems like you want to PACK:
b2 = PACK(b, mask=a>0) ! using a new var b2 (with size(b2)=count(a>0))
From: bing999 on
Thanks but PACK does not return the index of the array, right? i need
the index since my 2 arrays have same dimensions (and by the way my
problem is more complicated than just grab the positive values...)

From: Tom Micevski on
bing999 wrote:
> Thanks but PACK does not return the index of the array, right? i need
> the index since my 2 arrays have same dimensions (and by the way my
> problem is more complicated than just grab the positive values...)
>
i still think pack is what you want. if your required mask if quite
complicated, then just precalculate it (the mask array is just an array
of logicals) and use it with pack. eg.

fancy_mask = (a>0 .and. mod(a,2)==0)
allocate (b2(count(fancy_mask))) ! must allocate b2 to correct size
b2 = PACK(b, mask=fancy_mask) ! extracts elements of b where
! fancy_mask=.TRUE.