Silverfrost Forums

Welcome to our forums

Find values satsfying condition in array

17 Jan 2024 1:55 #30970

Hello

Is there a way to find the indices in array where a condition is satisfied and then extract those values. The equivalent in Matlab/Scilab:

values = x(find(x > 4.7)) where x is an array of real or integer values.

Pretty sure it must revolve around the use of findloc, but an example would be useful.

Thanks

Lester

17 Jan 2024 3:22 #30971

This will work, but cannot figure out how the same can be done via findloc:

program FindValuesGreaterThan2
  implicit none
  integer, parameter :: n = 10
  real :: testArray(n)
  integer :: indices(n)
  real, dimension(:), allocatable :: newArray
  integer :: count, i

  ! Initialize the test array with some values
  testArray = [1.0, 3.0, 2.0, 5.0, 0.0, 4.0, 2.5, 6.0, 1.5, 3.5]

  ! Find indices where values are greater than 2
  indices = 0  ! Initialize indices array with zeros
  count = 0    ! Initialize count

  do i = 1, n
    if (testArray(i) > 2.0) then
      count = count + 1
      indices(count) = i
    end if
  end do

  ! Allocate memory for the new array
  allocate(newArray(count))

  ! Extract values greater than 2 to the new array
  do i = 1, count
    newArray(i) = testArray(indices(i))
  end do

  ! Print the original and new arrays
  print *, 'Original array:', testArray
  print *, 'Values greater than 2:', newArray

  ! Deallocate the memory
  deallocate(newArray)

end program FindValuesGreaterThan2
17 Jan 2024 5:10 (Edited: 19 Jan 2024 1:51) #30972

There are a number of intrinsic functions that operate on arrays, such as PACK, MERGE, etc., whose purpose is to perform operations of the type sought.

program FindValuesGreaterThan2
  implicit none
  integer, parameter :: n = 10
  real :: testArray(n)
  integer :: indices(n)
  integer :: i, nsel
  integer, allocatable :: selIdx(:)

  ! Initialize the test array with some values
  testArray = [1.0, 3.0, 2.0, 5.0, 0.0, 4.0, 2.5, 6.0, 1.5, 3.5]
  indices = [(i,i=1,n)]
  ! Select and list elements > 4.7
  selIdx = pack(indices,testArray > 4.7)
  nsel = size(selIdx)
  print '(1x,2i3,F4.1)',(i,selIdx(i),testArray(selIdx(i)),i=1,nsel)

end program FindValuesGreaterThan2
18 Jan 2024 2:24 #30976

Many thanks for the suggestion and syntax example.

19 Jan 2024 12:17 #30977

mecej4,

Did you compile your example before posting ? looks like you didn't, so not bad for no checking.

Here is my (tested) example showing mecej4's new F90 way and mine and (Eddie's?) old way using DO loops.

program FindValuesGreaterThan2
 
  integer, parameter :: n = 10
  real :: testArray(n)
  testArray = [1.0, 3.0, 2.0, 5.0, 0.0, 4.0, 2.5, 6.0, 1.5, 3.5]

  call old_DO_way ( testArray,n )
  call new_pack_way ( testArray,n )
end program FindValuesGreaterThan2
  
subroutine new_pack_way ( testArray,n )
    implicit none
  integer :: n
  real :: testArray(n)
  integer :: indices(n)
  integer :: nsel, i
  integer, allocatable :: selIdx(:)

  ! Initialize the test array index
  indices = [(i,i=1,n)]
  ! Select and list elements > 4.7
  selIdx = pack(indices,testArray > 4.7)
  nsel = size(selIdx)

  print '(1x,2i3,F4.1)',(i,selIdx(i),testArray(selIdx(i)),i=1,nsel)

end subroutine new_pack_way

SUBROUTINE old_DO_way  ( testArray,n )
  implicit none
  integer :: n
  real :: testArray(n)
  integer :: nsel, i
  integer :: selIdx(n)

  ! generate a list of values
  nsel = 0
  do i = 1,n
    if ( testArray(i) <= 4.7 ) cycle
    nsel = nsel+1
    selIdx(nsel) = i
  end do

  print '(1x,2i3,F4.1)',(i,selIdx(i),testArray(selIdx(i)),i=1,nsel)

end SUBROUTINE old_DO_way 

I still prefer to see DO loops to show what is happening. After these comments, I hope my code doesn't need correcting !

19 Jan 2024 3:12 #30978

Lester, you may wish to read Chapter 2 of Arjen Markus's book, Modern Fortran in Practice, https://books.google.com/books?id=pOH80J24R_gC&printsec=copyright#v=onepage&q=pack&f=false , where he gives several examples of expressing calculations compactly using arrays and array manipulation functions.

Please login to reply.