List Comprehension and Map

Hi,

In the case that you can’t filter out data before applying foo, this is about as efficient as it gets, since the time of calling those function wastly dominates the time it takes to make a few allocations along the way:


# since we want only the time necessary for execution but not for allocating, we need something to prevent calls from being compiled away entirely
julia> @noinline noop(x) = x
noop (generic function with 1 method)

# time it takes for the foo and bar calls only:
julia> @btime for x in $a
           noop(foo(x))
       end
  511.200 μs (0 allocations: 0 bytes)

julia> barinputs = filter!(>(0.5), foo.(a));

julia> @btime for x in $barinputs
           noop(bar(x))
       end
  2.552 ms (0 allocations: 0 bytes)

so this is fairly optimal already:

julia> b3 = @btime bar.(filter!(>(0.5), foo.($a)));
  3.057 ms (2 allocations: 1.31 KiB)

In case you worry about the allocations: if you are fine with overwriting your input a, you can get rid of those, but unless the immediate values are huge in storage, the net gain is negligible:

julia> function foowithoutallocations!(a)
           @inbounds for i in eachindex(a)
               a[i] = foo(a[i])
           end
           a
       end
foowithoutallocations! (generic function with 1 method)

julia> function barwithoutallocations!(a)
           @inbounds for i in eachindex(a)
               a[i] = bar(a[i])
           end
           a
       end
barwithoutallocations! (generic function with 1 method)

julia> b4 = @btime barwithoutallocations!(filter!(>(0.5), foowithoutallocations!(acopy))) setup = (acopy=copy(a));
  3.025 ms (0 allocations: 0 bytes)

I’d throw in this for readability:

julia> b5 = @btime [bar(c) for c in foo.($a) if c > 0.5];
  3.083 ms (6 allocations: 2.86 KiB)