selecting array elements with a logical array
Author Message selecting array elements with a logical array

Hi all,
I suspect this is a stupid question, but I've got myself stuck. I have
a two dimensional array of data and I want to extract the elements
from each column where a second one dimensional array is between
certain limits. To explain further, the following function does what I
want. Here, x is a one dimensional array specifying the grid on which
each column of my data array is based. lims is a 2-element array
containing the lower and upper limits between which I want to select
from the grid and array is the two dimensional data array.
Note that the elements of x between lims may not be contigous. This
function works, but it seems a bit heavy handed. At first I thought I
should be able to just subscript the array like array(iis,:), but that
doesn't work (I guess the logicals are converted to integers right?).
Is there a simpler way to do this. I would have though it is quite
common. Thanks for any help!

Best regards,
John

function take(x, lims, array)
real, allocatable, dimension(:,:) :: take
real, dimension(:), intent(in) :: x
real, dimension(2), intent(in) :: lims
real, dimension(:,:), intent(in) :: array
logical, dimension(size(x)) :: iis
integer nc
nc = size(array(1,:))
iis = (x >= lims(1)) .and. (x <= lims(2))
allocate(take(count(iis),nc))
take = reshape(pack(array, spread(iis, 2, nc)), [count(iis),
nc])
end function take

Sat, 10 Apr 2010 03:31:57 GMT  selecting array elements with a logical array

Quote:
> Hi all,
> I suspect this is a stupid question, but I've got myself stuck. I have
> a two dimensional array of data and I want to extract the elements
> from each column where a second one dimensional array is between
> certain limits. To explain further, the following function does what I
> want. Here, x is a one dimensional array specifying the grid on which
> each column of my data array is based. lims is a 2-element array
> containing the lower and upper limits between which I want to select
> from the grid and array is the two dimensional data array.
> Note that the elements of x between lims may not be contigous. This
> function works, but it seems a bit heavy handed. At first I thought I
> should be able to just subscript the array like array(iis,:), but that
> doesn't work (I guess the logicals are converted to integers right?).
> Is there a simpler way to do this. I would have though it is quite
> common. Thanks for any help!

> Best regards,
> John

>     function take(x, lims, array)
>         real, allocatable, dimension(:,:) :: take
>         real, dimension(:), intent(in) :: x
>         real, dimension(2), intent(in) :: lims
>         real, dimension(:,:), intent(in) :: array
>         logical, dimension(size(x)) :: iis
>         integer nc
>         nc = size(array(1,:))
>         iis = (x >= lims(1)) .and. (x <= lims(2))
>         allocate(take(count(iis),nc))
>         take = reshape(pack(array, spread(iis, 2, nc)), [count(iis),
> nc])
>     end function take

forall(j=1:nc) take(:,j) = pack(array(:,j),iis)

Sat, 10 Apr 2010 03:44:43 GMT  selecting array elements with a logical array

Quote:

> At first I thought I
> should be able to just subscript the array like array(iis,:), but that
> doesn't work (I guess the logicals are converted to integers right?).

Huh? No, the logicals aren't converted into anything. The form above
isn't a valid form, as you found out, so it pretty much doesn't make
sense to say what happens to it; nothing happens to it. Perhaps you mean
to say something like that the logicals would have to be integers for
this form to make sense instead of that the logicals "are converted" to
integers.

Quote:
> Is there a simpler way to do this.
>     function take(x, lims, array)
>         real, allocatable, dimension(:,:) :: take
>         real, dimension(:), intent(in) :: x
>         real, dimension(2), intent(in) :: lims
>         real, dimension(:,:), intent(in) :: array
>         logical, dimension(size(x)) :: iis
>         integer nc
>         nc = size(array(1,:))
>         iis = (x >= lims(1)) .and. (x <= lims(2))
>         allocate(take(count(iis),nc))
>         take = reshape(pack(array, spread(iis, 2, nc)), [count(iis),
> nc])
>     end function take

Well, simplicity is a bit in the mind of the beholder. That being
said...

You've got 4 executable statements. I can't see much to improve in the
first 3. For the last one, I think you have the central part down in
using the pack intrinsic, but I personally find the spread and reshape
stuff a bit hard to follow. (In fact I'm just going to assume I
understand it correctly; I'd have to go through it more carefully to be
sure it was correct.)

I'd dispense with the spread/reshape bit by using a loop as in

do i = 1 , nc
take(:,i) = pack(array(:,i),iis)
end do

I can see what is going on there, while I'd have to carefully study the
spread/reshape thng to even be sure it was right.

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

Sat, 10 Apr 2010 04:04:33 GMT

 Page 1 of 1 [ 3 post ]

Relevant Pages