fortran найти серию целых чисел в массиве

Есть ли функция или метод в Fortran для поиска в виде серии целых чисел в массиве и возврата местоположения в массиве или подсчета, если они совпадают?

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

найти (8,56,33)

либо вернуть 3 в качестве местоположения, либо 1 в качестве совпадения

Если несколько:

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

найти (8,56,33)

Возврат 3 и 10 или 2

Существуют ли функции в фортране для обработки такого поиска в массиве?


person mchael    schedule 18.09.2019    source источник
comment
Не совсем то, что вам нужно, но взгляните на findloc   -  person PTRK    schedule 18.09.2019
comment
Чтобы завершить мой предыдущий комментарий, findloc был добавлен в gfortran 9.0 и ifort 19   -  person PTRK    schedule 18.09.2019


Ответы (2)


Короткий ответ: "Нет", в Фортране нет такой внутренней функции.

Обычно ожидается, что вы сами напишете что-то подобное. Например:

  • начать с массива всех возможных начальных индексов
  • определить условие сохранения индексов
  • последовательно сохраняйте только те индексы, которые удовлетворяют вашему условию

Встроенная процедура pack здесь весьма полезна, ее можно использовать только для сохранения значений из массива ( ваши стартовые локации), которые соответствуют определенному условию (вашему условию сохранения стартовых локаций).

Программа "test.f90" (не проверенная!) ниже иллюстрирует использование:

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

Для двух тестовых случаев в вашем вопросе компиляция и запуск дают следующий результат:

$ 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

а также

 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
person jbdv    schedule 18.09.2019
comment
Если вы работаете с большими массивами, вы можете изменить подпрограмму find_start_locs, чтобы использовать метод, описанный в @kvantour answer, чтобы создавать start_locs вместо удаления, как это делаю я. В дополнение к начальным накладным расходам моя условная маска в pack требует доступа к несмежным элементам array, в то время как скользящее окно обращается к элементам более непрерывно. - person jbdv; 19.09.2019

То, что вам нужно, называется алгоритмом поиска в скользящем окне. Простая реализация будет следующей:

program test
  implicit none

  integer, dimension(:), allocatable :: arr 
  integer, dimension(:), allocatable :: seq
  integer                            :: i

  arr = [1, 5, 8, 56, 33, 56, 78, 123, 78, 8, 56, 33, 19, 25, 36]
  seq = [8, 56, 33]

  do i=1,size(arr)-size(seq)+1
     if (all(arr(i:i+size(seq)-1) == seq)) print *, i
  end do
end program

Это не самая оптимизированная версия, но в большинстве случаев она подойдет.

person kvantour    schedule 18.09.2019