# Why does 'map' recompile each time?

Consider the follosing example:

``````y = [1 2 3]
@time findall(map( x-> x.== 3, y))
0.077566 seconds (69.12 k allocations: 4.160 MiB, 13.08% gc time, 99.57% compilation time)
1-element Vector{CartesianIndex{2}}:
CartesianIndex(1, 3)
``````

Why is the function recompiled each time I call it?

Because you’re defining a new anonymous function for each invocation.

3 Likes

To see this:

``````julia> f = x -> x .== 3
#57 (generic function with 1 method)

julia> @time findall(map(f, y))
0.030139 seconds (72.98 k allocations: 4.008 MiB, 98.57% compilation time)
1-element Vector{CartesianIndex{2}}:
CartesianIndex(1, 3)

julia> @time findall(map(f, y))
0.000016 seconds (3 allocations: 160 bytes)
1-element Vector{CartesianIndex{2}}:
CartesianIndex(1, 3)
``````
2 Likes

The dot in `.==` is for broadcasting, it ‘maps’ the operator over its input collection. So it’s redundant here, the argument of `map` is also mapped over the collection. Therefore, you should drop it: `map( x->x==3, y)`, not `map( x-> x.== 3, y)`.

Furthermore, `findall` takes a ‘mapped’ function as its first argument, too, so you can just do this instead:

``````findall( x->x==3, y)
``````

Or, more tersely,

``````findall(==(3), y)
``````

No reason to use `findall`, `map` and broadcast, when just `findall` will do.

2 Likes

Note that if it’s inside a function, a closure will only be compiled once:

``````julia> y = [1, 2, 3];

julia> @time findall(x -> x == 3, y);
0.038798 seconds (79.31 k allocations: 4.512 MiB, 99.87% compilation time)

julia> foo(y) = findall(x -> x == 3, y);

julia> @time foo(y);
0.037377 seconds (80.87 k allocations: 4.604 MiB, 99.96% compilation time)

julia> @time foo(y);
0.000003 seconds (1 allocation: 80 bytes)
``````
2 Likes