For these kinds of problems I find it convenient to define the .in. operator, which returns whether or not a scalar is in an array, so:
1 .in. [0, 1, 2] returns .true.
3 .in. [0, 1, 2] returns .false.
[1, 3] .in. [0, 1, 2] returns [.true., .false.]
This can be defined as
module in_module
implicit none
interface operator(.in.)
module procedure element_in_list
module procedure elements_in_list
end interface
contains
function element_in_list(lhs, rhs) result(output)
integer, intent(in) :: lhs
integer, intent(in) :: rhs(:)
logical :: output
output = any(lhs==rhs)
end function
function elements_in_list(lhs, rhs) result(output)
integer, intent(in) :: lhs(:)
integer, intent(in) :: rhs(:)
logical, allocatable :: output(:)
integer :: i
output = [(any(lhs(i)==rhs), i=1, size(lhs))]
end function
end module
With the .in. operator defined, then if X is an array you can write
where (.not. (X .in. [0, 1, 2, 16, 18])) X = -9999
which will convert e.g. X = [4, 5, 1, 3, 16] to X = [-9999, -9999, 1, -9999, 16].
If you want to simplify things further (as the where construct can be quite unwieldy), you can also define the function filter which takes an array of logicals and returns the indices of the .true. values, e.g. filter([.false., .true., .true.]) returns [2, 3].
This can be defined as:
function filter(input) result(output)
logical, intent(in) :: input(:)
integer, allocatable :: output(:)
integer :: i
output = pack([(i, i=1, size(input))], input)
end function
And then you can simply write
X(filter(.not. (X .in. [0, 1, 2, 16, 18]))) = -9999