julia - Is there a lazy `filter` in Julia?
问题描述
In Python one can use if
in the list comprehension to filter out elements. In Julia is there a lazy filter
equivalent?
for x in filter(x->x<2, 1:3)
println(x)
end
works and prints only 1
but filter(x->x<2, 1:3)
is eager and so may not be desirable for billions of records.
解决方案
您可以像在 Python 中一样执行此操作:
julia> function f()
for x in (i for i in 1:10^9 if i == 10^9)
println(x)
end
end
f (generic function with 1 method)
julia> @time f()
1000000000
3.293702 seconds (139.87 k allocations: 7.107 MiB)
julia> @time f()
1000000000
3.224707 seconds (11 allocations: 352 bytes)
你看到它没有分配。但是在不使用生成器的情况下只在循环内执行过滤器测试会更快:
julia> function g()
for x in 1:10^9
x == 10^9 && println(x)
end
end
g (generic function with 1 method)
julia> @time g()
1000000000
2.098305 seconds (53.49 k allocations: 2.894 MiB)
julia> @time g()
1000000000
2.094018 seconds (11 allocations: 352 bytes)
编辑最后你可以使用Iterators.filter
:
julia> function h()
for x in Iterators.filter(==(10^9), 1:10^9)
println(x)
end
end
h (generic function with 1 method)
julia>
julia> @time h()
1000000000
0.390966 seconds (127.96 k allocations: 6.599 MiB)
julia> @time h()
1000000000
0.311650 seconds (12 allocations: 688 bytes)
在这种情况下,这将是最快的(另请参阅https://docs.julialang.org/en/latest/base/iterators/#Iteration-utilities-1)。
您可能还想查看https://github.com/JuliaCollections/IterTools.jl。
编辑 2
有时 Julia 比你想象的更强大。看一下这个:
julia> function g2()
for x in 1:1_000_000_000
x == 1_000_000_000 && println(x)
end
end
g2 (generic function with 1 method)
julia>
julia> @time g2()
1000000000
0.029332 seconds (62.91 k allocations: 3.244 MiB)
julia> @time g2()
1000000000
0.000636 seconds (11 allocations: 352 bytes)
我们看到编译器基本上已经编译出了我们所有的计算。
从本质上讲 - 在前面的示例中,常量传播开始并在示例中10^9
被替换。1_000_000_000
Iterators.filter
因此,我们必须设计一个更智能的测试。它是这样的:
julia> using BenchmarkTools
julia> function f_rand(x)
s = 0.0
for v in (v for v in x if 0.1 < v < 0.2)
s += v
end
s
end
f_rand (generic function with 1 method)
julia> function g_rand(x)
s = 0.0
for v in x
if 0.1 < v < 0.2
s += v
end
end
s
end
g_rand (generic function with 1 method)
julia> function h_rand(x)
s = 0.0
for v in Iterators.filter(v -> 0.1 < v < 0.2, x)
s += v
end
s
end
h_rand (generic function with 1 method)
julia> x = rand(10^6);
julia> @btime f_rand($x)
2.032 ms (0 allocations: 0 bytes)
14922.291597613703
julia> @btime g_rand($x)
1.804 ms (0 allocations: 0 bytes)
14922.291597613703
julia> @btime h_rand($x)
2.035 ms (0 allocations: 0 bytes)
14922.291597613703
现在我们得到了我最初期望的结果(一个普通的循环if
是最快的)。
推荐阅读
- javascript - 使用 Javascript 在脚本中的 DIV 中的动态 Img Src URL
- amazon-web-services - 将 DynamoDB 事件发送到 Pinpoint
- javascript - TypeError:Products.find 不是(react/typescript)中的函数
- xml - 使用 RFC 5261 使用 Laravel Guzzle 修补 XML 文档
- html - 表情符号在 Windows 10 浏览器中渲染太大
- .net - 对 Authenticode .NET Framework 库和可执行文件有何影响
- spring-data-jpa - 我需要根据应用程序捕获第一个触发日期时间并将标志设置为“N”,因为未收到确认
- angular - 使用带有 ng-template 的动态组件的问题
- javascript - 反应状态没有更新 UI
- javascript - Javascript:通过参考对象计算图像中对象的大小