Reputation: 300
I am writing a Fortran90 subroutine, but the language does not matter for the purpose of this question. Feel free to provide answers in psuedocode if it's more convenient.
I have a number statements (or groups of statements) to execute based on an input parameter. Let the input variable be x
and let's call the statements A, B, C,..., N. These statements do not share enough common properties to be combined, and should therefore be executed separately.
The conditions are:
if ( x .eq. 1 ) then
! execute A
endif
if ( x .eq. 2 ) then
! execute A
! execute B
if ( x .eq. 3 ) then
! execute A
! execute B
! execute C
endif
.
.
.
and so on...
(Note that all the ! execute
statements are all mathematical calculations and variable assignments. Nothing is printed, no functions are called, etc...)
My attempt to simplify the code turned it into:
if ( x .ge. 1 ) then
! execute A
endif
if ( x .ge. 2 ) then
! execute B
endif
if ( x .ge. 3 ) then
! execute C
endif
.
.
.
This is still too much coding to do for a large value of x
. I know that I have to code all the execute
statements (and I have already done so), but I am hoping that there is still a faster way to only run the number that the user specifies without having to type over a hundred if
statements. Any thoughts on that?
Upvotes: 2
Views: 169
Reputation: 6989
I might do something like this:
i=howmany
do while(i.gt.0)
< a code >
i=i-1;if(i.eq.0)exit
< b code >
i=i-1;if(i.eq.0)exit
<c code>
i=i-1;if(i.eq.0)exit
<d code>
exit
enddo
or equivalently use a subroutine with return.
Note this is logically equivalent to where you started, but the conditional line is the same so a lazy typist can quickly do ctrl-y ctrl-y ctrl-y
Another advantage of this is, should you need to edit the lines you can insert/delete a line anywhere without manually reindexing.
Upvotes: 1
Reputation: 858
What about a recursive subroutine? Something like this:
recursive subroutine select(x)
integer,intent(in) :: x
select case(x)
case(1)
!execute A
case(2)
!execute B
case(3)
!execute C
end select
if(x > 0) call select(x-1)
end subroutine select
Again, this goes backwards, but a forward version shouldn't be too hard. And there's always the stack overflow possibility if you have a lot of these. This is essentially getting rid of the explicit loop in the accepted answer.
Upvotes: 1
Reputation: 78314
Oh what a shame that computed go to
is frowned upon. No self-respecting Fortran programmer in C21 would write something like
...
read(*,*) x
go to (3,2,1) x
1 call C()
2 call B()
3 call A()
Of course, this executes the calls
in the reverse order to that specified in the question, but the question also hints that the order doesn't matter.
I'll close this by reminding readers that this is definitely nasty old FORTRAN. Let us not speak of this again
Upvotes: 6
Reputation: 18098
You could use one-line versions of if
:
if ( x .ge. 1 ) call ... ! execute A
if ( x .ge. 2 ) call ... ! execute B
...
Or, if processed within a subroutine
or function
, you could use return
:
call ... ! execute A
if ( x .lt. 2 ) return
call ... ! execute B
if ( x .lt. 3 ) return
...
It's also possible to do this in one line per statement:
call ... ; if ( x .lt. 2 ) return ! execute A
call ... ; if ( x .lt. 3 ) return ! execute B
I don't think it will get less than that, even when using function pointers you would have to point them to the corresponding function/subroutine (which also amounts to one line per function)...
Upvotes: 2
Reputation: 8257
Not exactly an ideal solution since F90 doesn't have function pointers. Could do it in F03 with function pointers but since you have specified F90
subroutine selector(howmany)
integer, intent(in):: howmany
integer:: ii
do ii = 1, howmany
select case(ii)
case (1)
! execute A
case (2)
! execute B
case (3)
! execute C
case default
continue
end select
end do
end subroutine selector
...
call selector(3)
Unlike C, fortran doesn't have a dropthrough
Upvotes: 4