朱莉娅有一个懒惰的“过滤器”吗?

xia*_*dai 4 julia

在Python中,可以if在列表推导中使用以滤除元素。在朱莉娅中有一个懒惰的对filter等物吗?

for x in filter(x->x<2, 1:3)
println(x)
end
Run Code Online (Sandbox Code Playgroud)

仅能工作和打印,1filter(x->x<2, 1:3)渴望并且因此对于数十亿条记录可能不是理想的。

Bog*_*ski 9

您可以像在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)
Run Code Online (Sandbox Code Playgroud)

并且您看到它没有分配。但是,不使用生成器而仅在循环内执行过滤器测试会更快:

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)
Run Code Online (Sandbox Code Playgroud)

编辑最后,您可以使用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)
Run Code Online (Sandbox Code Playgroud)

在这种情况下最快(请参见https://docs.julialang.org/en/latest/base/iterators/#Iteration-utilities-1)。

您可能还想查看https://github.com/JuliaCollections/IterTools.jl

编辑2

有时候,朱莉娅比你想像的要强大。看一下这个:

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)
Run Code Online (Sandbox Code Playgroud)

我们看到编译器实质上已经编译了我们所有的计算。

本质上-在前面的示例中,恒定传播10^91_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
Run Code Online (Sandbox Code Playgroud)

现在,我们达到了我最初的期望(if最快的循环)。

  • 知道为什么`Iterator.filter`这么快吗? (2认同)
  • 啊-编译器优化开始了。我将在答案中对它们进行扩展。 (2认同)