This question is an extension if one I asked earlier today。基本上,我试图在Julia中编写一个数组理解,调用一个函数f(x)
,其输出是一个随机数。当达到小于0.5的随机数时,我希望它杀死该函数。我能够编写以下代码:
X = [f(i)for i in 1:1:100 if(j = f(i); j <0.5?false:j> 0.5)]
这个问题是这会调用两个单独的f(x)
实例,并且因为f(x)
每次都是随机的,所以上面不会在正确的实例中杀死for循环。我试过了
X = [J = f(i)for i in 1:1:100 if(J <0.5?false:J> 0.5)]
作为尝试保存该特定随机数,但它告诉我J未定义。有没有办法保存这个特定的随机数来执行我的数组理解?
答案 0 :(得分:6)
坚持使用@TasosPapastylianou的单线解决方案,快速的解决方案将是:
X = ( r=Vector{Float64}() ;
any(i->(v=f(i) ; v>0.5 ? ( push!(r,v) ; false) : true), 1:100)
; r )
[单行被分成三行,因为它有点长;)]
由于缺少f
,因此请使用rand
对此版本进行复制粘贴:
(r=ones(0); any(i->(v=rand(); v>0.5 ? (push!(r,v); false) : true), 1:10); r)
它的基准测试比凤阳的功能慢了约10%。聪明的位正在利用any
的短路实现。
ADDENDUM :这里概括一下凤阳的takewhile
版本来抽象这个问题的答案:
collectwhilecond(f,cond,itr) = begin
r=Vector{typeof(f(first(itr)))}()
all(x->(y=f(x); cond(y) ? (push!(r,y);true):false),itr)
return r
end
现在,我们可以将上面的答案实现为(joker
为f
):
julia> joker(i) = 1.0 + 4*rand() - log(i)
julia> collectwhilecond(joker, x->x>=0.5, 1:100)
3-element Array{Float64,1}:
4.14222
3.42955
2.76387
如果Julia推断collectwhilecond
的返回类型, f
也是类型稳定的。
编辑:使用@ tim的推荐方法推断f
的返回类型,而不会提取itr
元素而不会冒不稳定{{1}的风险}生成错误,新的f
是:
collectwhilecond
答案 1 :(得分:5)
您尝试做的事实上是一个简单的filter
操作:
filter(x -> x >= 0.5, [f(i) for i in 1:10])
这基本上是我们在v0.5之前在julia中的列表推导中实现if
部分之前首先依赖的东西
编辑:正如Dan指出的那样,你可能在保留所有元素之后直到第一个元素为&lt; 0.5而不是,例如:
L = [f(i) for i in 1:10]; L[1 : findfirst(L.<0.5) - 1]
然而,在这种情况下,正如其他人所指出的那样,你也可以选择正常的for循环。列表推导将始终首先处理整个列表,因此它不会更快。您可以使用生成器,但是您必须创建自己的特殊机制才能使其停在正确的状态(正如凤阳建议使用takewhile
)。
所以为了回答评论中的问题,在这种情况下你能做的最快的事情是正常的for循环,它会适当地破坏。此外,它最好包含在函数中而不是全局计算,如果指定变量的类型,它将进一步加速。
答案 2 :(得分:4)
你可以使用生成器上通常称为takewhile
的内容
X = collect(takewhile(x -> x ≥ 0.5, Generator(f, 1:100)))
需要takewhile
的实现,例如this blog post中的实现,或者您自己的实现(这不是很难)。 takewhile
有一个相当容易阅读的名称,并且尽可能简洁。
但是我认为编写循环通常更具可读性和方便性:
X = Float64[]
for i = 1:100
j = f(i)
if j < 0.5
break
else
push!(X, j)
end
end
答案 3 :(得分:3)
正如所建议的,使用循环是正确的方法。但是,如果尝试“其他”解决方案,以下内容很简短,并且对于在Stack Overflow中很少提及的频道很有教育意义:
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<nav class="navbar navbar-default">
<div class="container-fluid">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<div class="navbar-left">
<img class="navbar-logo" src="img/logo.png">
</div>
</div>
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav">
<li class="active"><a href="#">Home <span class="sr-only">(current)</span></a></li>
<li><a href="#">About me</a></li>
<li><a href="#">Portfolio</a></li>
<li><a href="#">Services</a></li>
<li><a href="#">Blog</a></li>
</ul>
<form class="navbar-form navbar-right">
<div class="form-group">
<input type="text" class="form-control" placeholder="Search website">
</div>
<button type="submit" class="btn btn-default">Search</button>
</form>
</div>
<!-- /.navbar-collapse -->
</div>
<!-- /.container-fluid -->
</nav>
根据需要将collect(Channel(c->begin
i=1
while true
v = rand()
if v<0.5 || i>100 return else put!(c,v) end
i+=1
end
end, ctype=Float64))
替换为rand()
。
BTW不使用此解决方案,因为它比简单循环慢1000倍。如果Channel是RemoteChannel并且f(i)
是一个大的随机模拟,则可能有价值。
答案 4 :(得分:2)
如果你想挤出最大可能的性能,我说有两种选择取决于哪个瓶颈。
f
非常快,但分配是一个问题。以下代码计算f
两次但保存在分配部分(因为push!
有时会重新分配内存,请参阅here): i = findfirst(t -> f(t) > 0.5, 1:100)
w = f.(1:(i-1))
f
非常慢,计算两次太贵了。然后按照已经推荐的方式使用push!
进行循环。您可能需要查看sizehint!
以进一步提高效果。一般情况下,您不需要问慢速度和速度更快:ypu可以使用优秀的BenchmarkTools软件包对您的特定用例进行基准测试。