在 Julia 数组理解中杀死 For 循环

Killing a For loop in Julia array comprehension

我在 Julia 中有以下代码行:

X=[(i,i^2) for i in 1:100 if i^2%5==0]

基本上,如果 i^25 的余数为零,它 returns 来自 i=1 to 100 的元组列表 (i,i^2)。我想要做的是,在数组理解中,如果 i^2 变得大于 1000,则跳出 for 循环。但是,如果我实施

X=[(i,i^2) for i in 1:100 if i^2%5==0 else break end]

我收到错误:syntax: expected "]"

有什么方法可以轻易地跳出数组中的这个for循环吗?我试过在线查找,但没有任何结果。

我不这么认为。你总是可以

tmp(i) = (j = i^2; j > 1000 ? false : j%5==0)
X=[(i,i^2) for i in 1:100 if tmp(i)]

这是一个 "fake" for 循环,所以你不能 break 它。看看下面降低的代码:

julia> foo() = [(i,i^2) for i in 1:100 if i^2%5==0]
foo (generic function with 1 method)

julia> @code_lowered foo()
LambdaInfo template for foo() at REPL[0]:1
:(begin 
        nothing
        #1 = $(Expr(:new, :(Main.##1#3)))
        SSAValue(0) = #1
        #2 = $(Expr(:new, :(Main.##2#4)))
        SSAValue(1) = #2
        SSAValue(2) = (Main.colon)(1,100)
        SSAValue(3) = (Base.Filter)(SSAValue(1),SSAValue(2))
        SSAValue(4) = (Base.Generator)(SSAValue(0),SSAValue(3))
        return (Base.collect)(SSAValue(4))
    end)

输出显示 array comprehension 是通过 Base.Generator 实现的,它将迭代器作为输入。目前只支持[if cond(x)::Bool]"guard",所以这里没办法使用break

对于您的具体情况,解决方法是使用 isqrt:

julia> X=[(i,i^2) for i in 1:isqrt(1000) if i^2%5==0]
6-element Array{Tuple{Int64,Int64},1}:
 (5,25)  
 (10,100)
 (15,225)
 (20,400)
 (25,625)
 (30,900)

使用 for 循环在 Julia 中被认为是惯用的,在这种情况下可能更具可读性。另外,它可能会更快。

具体来说:

julia> using BenchmarkTools

julia> tmp(i) = (j = i^2; j > 1000 ? false : j%5==0)
julia> X1 = [(i,i^2) for i in 1:100 if tmp(i)];

julia> @btime [(i,i^2) for i in 1:100 if tmp(i)];
  471.883 ns (7 allocations: 528 bytes)

julia> X2 = [(i,i^2) for i in 1:isqrt(1000) if i^2%5==0];

julia> @btime [(i,i^2) for i in 1:isqrt(1000) if i^2%5==0];
  281.435 ns (7 allocations: 528 bytes)

julia> function goodsquares()
           res = Vector{Tuple{Int,Int}}()
           for i=1:100
               if i^2%5==0 && i^2<=1000
                   push!(res,(i,i^2))
               elseif i^2>1000
                   break
               end
           end
           return res
       end
julia> X3 = goodsquares();

julia> @btime goodsquares();
  129.123 ns (3 allocations: 304 bytes)

因此,另外 2 倍的改进不容忽视,长函数为阐明评论提供了充足的空间。