Search code examples
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:

    • begin with an array of all possible starting indices
    • determine a condition for keeping indices
    • sequentially keep only those indices that satisfy your condition

    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