Can select case (n) where n is a variable integer?

Dear all,

A naive question, if I have 100 cases, which depend on different integer variables n1, n2, n3, … n100, can I do like

! n1, n2, n3, ... n100 are all variables which has been precalcualted. However they are not parameters/constants.
function fcn(x)
real :: x(:)
integer :: n
n = size(x)
select case (n)
case (n1)
! n=n1, do some stuff
case(n2)
! n=n2, do some stuff
...
case(n100)
! n=n100, do some stuff
end select
end function fcn

But of course it does not work because case(xx) the xx has to be a constant integer.

Does that mean, I have to do a big 'if then else` ? like,

if (n==n1) then
! xxxxxxxxx
else if (n==n2) then
! xxxxxxxxx
else if (n==n3) then
! xxxxxxxxx
...
else if (n==n100) then
! xxxxxxxxx
else
    stop ('this n is not defined, stop')
endif

Is it slow?
Is there better way to handle such situation which consists many cases?

Thanks much in advance!

It is unusual to have that many cases that do not fall into groups. An actual case would probably garner a more useful answer. There are always other ways, including creating a procedure for each case and pointing to the correct procedure, a computed GOTO, and setting a logical array with values and then after the selection(s) have been made execute a second block of code with execution based on the logical values. The speed depends on the compiler implementation but because of the restrictions placed on a select case (values much be constants, no duplicate case statements, …) it should be theoretically the fastest when the variable is frequently changing. Do you dislike something about the construct? SELECT CASE is considered an improvement (well, by most) over the ambiguity of a large if/elseif/else/endif and the general campaign to eliminate anything resembling a GOTO and was added to Fortran as an enhancement. Some would have preferred that SELECT be required to be exhaustive (that basically means all possible values for a SELECT variable have a CASE; which often just means you must have a CASE DEFAULT, and would take a lot of work for a small return for the compiler to know the default is not needed (if the variable was logical it would be easy, for an ENUM easy; but for many other cases difficult or not possible, so better left to the programmer). So IMO the question cannot be properly answered much beyond that without an actual use case.

3 Likes

You can create an array containing the various possible values of n. When you wish to select the code for a particular value of n, search that table, and use the index of the value that matches as the select case number.

! n1, n2, n3, ... n100 are all variables
integer nn(100) = [21, 33, ...] ! the different values possible for n
...
!search array for n
do idx = 1,100
   if(nn(idx) == n)exit
end do
if (idx == 101) idx=0
select case(idx)
   case(1)
      !n = nn(1)
      ...
   case(100)
      !n = nn(100)
      ...
   case default
      !error handling
end select

The linear search in the array nn could be improved upon, if necessary. You could compute and store the inverse index ninv() such that nn(ninv(k)) = k. Or you could sort the array nn and do a binary search. However, if the array is about 100 in size, the linear search should be fast enough.

1 Like

I very much doubt the time it takes to get to the right case with either a SELECT CASE or a list of IF/ELSEIF blocks would be measurable. And that time is likely to be dwarfed if the code for each case does more than one or two assignments. But in all such cases: you need to measure it to be sure :wink:

1 Like