繁体   English   中英

是否有与Python的for-else语句等效的Fortran?

[英]Is there a Fortran equivalent of Python's for-else statement?

是否有与Python的for-else语句等效的Fortran?

例如,以下将数字列表排序到不同的范围。 在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呢?

如果问题特别是关于对一系列数字进行absth ,而absth是每个箱柜的上限(最后一个酒吧没有上限),那么我可能会写这样的东西:

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结构,那么这里也有答案。

没有直接等效于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

并且cycle语句可以循环嵌套该语句的任何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

GO TO语句允许任意跳转。 特别是,您先编写for循环,然后再是else块,再加上一个标记为Continue的代码。 在循环内,如果条件为true,则跳至标记为继续。 否则,for循环将正常终止,else块将被执行,然后继续执行,完全匹配python for ... 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

由于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

根据第20.1.7节:“ 现代Fortran解释中的 “几乎从任何结构退出”(由Metcalf等人)以及F2008标准第8.1.10节 (从此处获得),可以从任何标记的结构退出像blockifassociate等,但是我们可能需要一个相对较新的编译器(gfortran-6为我工作)。 用于退出的IBM手册页也很有用。

就我所知,Python是仅有的(或少数几种)具有for-else语句的语言。 不,Fortran没有。

有时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))

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM