是否有一个Fortran相当于Python的for-else语句?
例如,以下内容将数字列表排序到不同的范围内。在Python中,它是:
absth = [1, 2, 3, 4, 5]
vals = [.1, .2, .5, 1.2, 3.5, 3.7, 16.8, 19.8, 135.60]
counts = [0] * len(absth)
for v in vals:
for i, a in enumerate(absth):
if v < a:
counts[i] += 1
break
else:
counts[-1] += 1
在Fortran中,它的工作方式相同:
do iv = 1, nvals
is_in_last_absth = .true.
do ia = 1, nabsth - 1
if vals(iv) < absth(ia) then
counts(ia) = counts(ia) + 1
is_in_last_absth = .false.
exit
end if
end do
if (is_in_last_absth) then
counts(nabsth) = counts(nabsth) + 1
end if
end do
但是有没有办法不必使用is_in_last_absth
并用Python中的else
替换它?
答案 0 :(得分:3)
如果问题是关于分组一系列数字的问题,absth
是每个bin的上限(最后一个没有上限),那么我可能会这样写:< / p>
PROGRAM test
IMPLICIT NONE
INTEGER :: ix
INTEGER, DIMENSION(5) :: absth = [1, 2, 3, 4, 5]
REAL, DIMENSION(9) :: vals = [.1, .2, .5, 1.2, 3.5, 3.7, 16.8, 19.8, 135.60]
INTEGER, DIMENSION(SIZE(absth)+1) :: bins
bins = 0
DO ix = 1, SIZE(bins)-1
bins(ix) = COUNT(vals<absth(ix))
END DO
bins(ix) = COUNT(vals)
bins = bins-EOSHIFT(bins,-1)
WRITE(*,*) 'bins = ', bins
! which writes 3 1 0 2 0 3
END PROGRAM test
然后,当我很高兴逻辑是正确的时,我会把它变成一个函数并添加一些错误检查。
如果问题更一般,并询问什么是惯用Fortran(后90)重现Python for-else
结构的方法,那么这里也有答案。
答案 1 :(得分:3)
没有直接等效于那个python构造。
但请注意,可以通过检查循环后do变量的值来检测带有计数循环控制的do循环的提前终止。
do iv = 1, nvals
do ia = 1, nabsth - 1
if (vals(iv) < absth(ia)) then
counts(ia) = counts(ia) + 1
exit
end if
end do
! If the loop terminates because it completes the iteration
! count (and not because the exit statement is executed) then
! the do variable is one step beyond the value it had
! during the last iteration.
if (ia == nabsth) then
counts(nabsth) = counts(nabsth) + 1
end if
end do
退出语句也可以跳出多个循环:
do iv = 1, nvals
outer_block: block
do ia = 1, nabsth - 1
if (vals(iv) < absth(ia)) then
counts(ia) = counts(ia) + 1
exit outer_block
end if
end do
counts(nabsth) = counts(nabsth) + 1
end block outer_block
end do
并且循环语句可以循环语句嵌套在其中的任何do构造:
outer_loop: do iv = 1, nvals
do ia = 1, nabsth - 1
if (vals(iv) < absth(ia)) then
counts(ia) = counts(ia) + 1
cycle outer_loop
end if
end do
counts(nabsth) = counts(nabsth) + 1
end do outer_loop
答案 2 :(得分:1)
GO TO语句允许任意跳转。特别是,你编写for循环后跟else块,然后标记为continue。在循环内,如果条件为真,则跳转到标记的继续。否则for循环将正常终止,else块将被执行然后继续,完全匹配python的语义为... else构造。
例如:
INTEGER nabsth, nvals
PARAMETER (nabsth=5, nvals=9)
INTEGER absth(nabsth), counts(nabsth)
REAL vals(nvals)
DATA absth/1, 2, 3, 4, 5/
DATA counts/0, 0, 0, 0, 0/
DATA vals/.1, .2, .5, 1.2, 3.5, 3.7, 16.8, 19.8, 135.60/
do iv = 1, nvals
do ia = 1, nabsth - 1
if (vals(iv) < absth(ia)) then
counts(ia) = counts(ia) + 1
goto 10
end if
end do
counts(nabsth) = counts(nabsth) + 1
10 continue
end do
WRITE (*,*), counts
end
可生产
3 1 0 2 3
答案 3 :(得分:1)
由于只有在处理了所有元素时才执行Python的for-else块的else
部分,如何简单地使用if
语句来表示最后一个元素?例如,
program main
implicit none
integer i, n
print *, "n = ?" ; read(*,*) n
do i = 1, 10
if ( i <= n ) then
print *, i
else
exit
endif
if ( i == 10 ) print *, "reached the final index"
enddo
print *, "done"
end program
可能对应
n = int( input( "n = ? \n" ) )
for i in range( 1, 11 ):
if i <= n:
print( i )
else:
break
else:
print( "reached the final index" )
print( "done" )
另一种方法可能是使用带标签的block
构造,例如:
program main
implicit none
integer i, n
print *, "n = ?" ; read(*,*) n
loop_i : block
do i = 1, 10
if ( i <= n ) then
print *, i
else
exit loop_i
endif
enddo
print *, "reached the final index"
endblock loop_i
print *, "done"
end program
根据Chap.20.1.7:&#34;退出几乎任何建筑物&#34;在现代Fortran解释(由Metcalf等人)和F2008标准Chap.8.1.10(从here获得)中,可以退出任何标记的构造,如{{1 },block
,if
等,但我们可能需要一个相对较新的编译器(gfortran-6为我工作)。 <{3}}的IBM手册页也很有用。
答案 4 :(得分:0)
据我所知,Python是唯一具有for-else语句的(或极少数)语言之一。不,Fortran没有它。
答案 5 :(得分:0)
有时GOTO很好。 在哪里可能有用......
do iv = 1, nvals
is_in_last_absth = .true.
Mask = .FALSE.
Mask(1:(nabsth - 1)) = .TRUE.)
Mask2 = .FALSE.
WHERE(MASK)
WHERE( vals(iv) < absth)
mask2 = .TRUE.
ENDWHERE
WHERE(Mask2)
Count = Count + 1
ELSE
LastCount = LastCount + 1
ENDWHERE
END WHERE
end do
count(2:(n-1)) = count(2:(n-1))+ lastcount(1:(n))