COMPGROUPS.NET | Search | Post Question | Groups | Stream | About | Register

### equivalent in fortran of the IDL "where" function

• Email
• Follow

```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
```
 0
Reply thibaultgarel (44) 3/26/2010 2:53:46 PM

See related articles to this posting

```On 26 mrt, 15:53, bing999 <thibaultga...@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 =3D [ 2,5,9,-7,4,-8]
> b =3D [ 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 =3D b(where(a ge 0)) in IDL =A0and it would give: b =3D 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 >=3D 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 =3D pack( b, a >=3D 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 >=3D 0 ) )
....
subroutine resize( b, fill )
integer, dimension(:), allocatable, intent(inout) :: b
integer, dimension(:), intent(in)                 :: fill

deallocate( b )
allocate( b(1:size(fill) )
b =3D 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 >=3D 0 ) )

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

Yet another way is:

b =3D (/ pack( b, a>=3D 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
```
 0

```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))
```
 0

```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...)

```
 0

```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.

allocate (b2(count(fancy_mask))) ! must allocate b2 to correct size
```
 0

```bing999 <thibaultgarel@gmail.com> 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...)

Ok. Pack does what your example shows, but apparently the example isn't
adequately representative. Another possibility is the Fortran WHERE
construct. It also doesn't return index values. In fact, it doesn't
return anything at all, being a construct instead of a procedure. But it
does allow you to do some things on the selected elements of multiple
arrays having the same dimensions. Admitedly, the things you can do are
very limitted.

Otherwise, if you really do want an array of the index values as you
say, then I'll give an answer much like that I gave to another recent
inquiry. Broaden your focus to realize that there are ways to operate on
arrays other than whole array expressions. It is pretty simple to do
this one with a DO loop. The only thing that makes it non-trivial is
that you don't know the size of the needed array of index values until
after the fact. You can address this either by determining the size as a
separate first step or by dimensioning the array to the maximum possible
size (which is the size of the original array).

As in

allocate (indices(count(condition-involving-array-a)))
n = 0
do i = 1 , size(a)
if (condition-involving-a(i)) then
n = n + 1
indices(n) = i
end if
end do

or

allocate(indices(size(a)))
... the same loop as above
! Optionally followed by
a = a(1:n) !-- Assuming f2003 allocatable assignment.

As an aside, note that an array of index values is not a particularly
handy form in Fortran in general. In particular, you can't directly use
such a thing for the multi-dimensional case; you'd have to break it
appart, probably in a loop. You can use it in the one-dimensional case,
but there are restrictions on the usage and, depending on details, you
might find it inefficient.

--
Richard Maine                    | Good judgment comes from experience;
email: last name at domain . net | experience comes from bad judgment.
domain: summertriangle           |  -- Mark Twain
```
 0

```Richard Maine wrote:
....

> Otherwise, if you really do want an array of the index values as you
> say, then I'll give an answer much like that I gave to another recent
> inquiry. Broaden your focus to realize that there are ways to operate on
> arrays other than whole array expressions. It is pretty simple to do
> this one with a DO loop. The only thing that makes it non-trivial is
> that you don't know the size of the needed array of index values until
> after the fact. You can address this either by determining the size as a
> separate first step or by dimensioning the array to the maximum possible
> size (which is the size of the original array).
....

And, I'll note for OP that while in environments such as IDL or Matlab
where there may be a significant performance penalty in looping
constructs as compared to figuring out how to vectorize the code, since
Fortran is compiled there will not be such a penalty at run time to
worry about.  The offsetting condition is it may take a little more
coding effort in Fortran than in one of these languages.

Also, there's a distinct possibility that the concise Fortran constructs
may not compile/optimize as well as the straightahead DO construct;
whether that's true or not will, of course, depend on the actual
construct as well as the specifics of a given compiler.

--
```
 0

```dpb <none@non.net> wrote:
(snip)

> And, I'll note for OP that while in environments such as IDL or Matlab
> where there may be a significant performance penalty in looping
> constructs as compared to figuring out how to vectorize the code, since
> Fortran is compiled there will not be such a penalty at run time to
> worry about.  The offsetting condition is it may take a little more
> coding effort in Fortran than in one of these languages.

and R and Mathematica.  After the question a few days ago, and then
this one, I was about to write the same thing.  The key to fast
code in such interpreted languages is using the array operations,
or even more specialized built-in operators.

> Also, there's a distinct possibility that the concise Fortran constructs
> may not compile/optimize as well as the straightahead DO construct;
> whether that's true or not will, of course, depend on the actual
> construct as well as the specifics of a given compiler.

The array operations can easily require temporary arrays that are
not needed in the DO loop case.  Using array operators tends to
require more passes through the array.  Also, like in the one a few
days ago, the DO case can often exit early without processing the
whole array.  The array operation case usually can't do that.

While compilers are getting better, I believe the statement that
I made years ago is still true:  Array operations are likely
at least as fast for simple operations, but often slower
(and also less readable) for more complicated operations.

They do make nice entries for Obfuscated Code contests, though.

-- glen
```
 0