fortranfortran90fortran95

fortran find series of integers in array


Is there a function or method in Fortran to find as series of integers in an array and return a location in the array or count if matches?

(1, 5, 8, 56, 33, 56, 78, 123, 78, 8, 34, 33, 19, 25, 36)

find (8,56,33)

either return 3 as location or 1 as a match

If multiple:

(1, 5, 8, 56, 33, 56, 78, 123, 78, 8, 56, 33, 19, 25, 36)

find (8,56,33)

Return 3 and 10 or 2

Are there functions in fortran to handle this kind of array searching?


Solution

  • The short answer is "No", there is no such intrinsic function in Fortran.

    You are typically be expected to write something like this yourself. For example:

    The intrinsic procedure pack is quite useful here, it can be used to only retain values from an array (your starting locations) that match a certain condition (your condition for keeping starting locations).

    The (not extensively tested!) program "test.f90" below illustrates the use:

    module mod_finder
        implicit none
    
        contains
            subroutine find_start_locs(array, sub_array, start_locs)
                integer, intent(in) :: array(:)
                integer, intent(in) :: sub_array(:)
                integer, allocatable, intent(out) :: start_locs(:)
                integer :: i
    
                ! initialize result with all possible starting indices
                start_locs = [(i, i = 1, size(array)-size(sub_array)+1)]
    
                ! sequentially keep only those indices that satisfy a condition
                do i = 1, size(sub_array)
                    ! condition for keeping: the value of array(start_locs + i - 1) must be equal to the value of sub_array(i)
                    ! use PACK to only keep start_locs that satisfy this condition
                    start_locs = PACK(start_locs, array(start_locs + i - 1) == sub_array(i))
                    if (size(start_locs) == 0) then
                        exit
                    end if
                end do
            end subroutine find_start_locs
    
    end module mod_finder
    
    program test
        use mod_finder
        implicit none
    
        integer, allocatable :: arr(:)
        integer, allocatable :: seq(:)
        integer, allocatable :: res(:)
    
        ! arr = [1, 5, 8, 56, 33, 56, 78, 123, 78, 8, 34, 33, 19, 25, 36]
        arr = [1, 5, 8, 56, 33, 56, 78, 123, 78, 8, 56, 33, 19, 25, 36]
        seq = [8, 56, 33]
    
        call find_start_locs(arr, seq, res)
    
        print *, "array:     ", arr
        print *, "sequence:  ", seq
        print *, "locations: ", res
        print *, "# matches: ", size(res)
    
    end program test
    

    For the two test cases in your question, compiling and running gives the following output:

    $ gfortran -O2 -g -Wall -Wextra -fcheck=all test.f90
    $ ./a.out
    
     array:                1           5           8          56          33          56          78         123          78           8          34          33          19          25          36
     sequence:             8          56          33
     locations:            3
     # matches:            1
    

    and

     array:                1           5           8          56          33          56          78         123          78           8          56          33          19          25          36
     sequence:             8          56          33
     locations:            3          10
     # matches:            2