If you want to spend your effort on making this code cleaner, the more 
Julian thing would be to focus on making it more type-generic, so that it 
can handle arguments of more types.  For example (requires Julia 0.5):

function mapeBase{T<:Number,S<:Number}(A::AbstractArray{T}, F::AbstractArray{S})
  indices(A) != indices(F) && error("arguments must be arrays of the same 
shape")

  s = zero(float(real(promote_type(T,S))))
  count = 0

  for i in eachindex(A)
    @inbounds if A[i] != 0
      s += abs((A[i] - F[i]) / A[i])
      count += 1
    end
  end
  return s, count 

end   

There is no performance penalty to declaring more generic function argument 
types.  When you pass in Vector{Float64} arrays, a version of mapeBase is 
specialized to that type and compiled, just as if you had declared those 
types.

Note, by the way, that this way of comparing two arrays is very susceptible 
to floating-point roundoff errors — think about what happens if A[i] is 
supposed to be 0.0, but is actually 1e-15 due to roundoff.    I would 
normally recommend something like vecnorm(A - F, 1) / vecnorm(A, 1) instead 
-- i.e. take the sum of the |A[i] - F[i]| and divide by the *sum* of |A[i]|.

I agree with other posters that this is a case in which a loop is much 
cleaner.  It is possible to solve this problem efficiently with reduce in 
0.5 (where higher-order functions are now fast), but it would require much 
more careful coding and the resulting code would be much more obscure and 
unmaintainable, nor would a reduce-based implementation be much shorter as 
you have seen.

Higher-order functions are great, and it is great to use them where they 
simplify your code.  But sometimes a loop is cleaner, and (unlike in other 
dynamic languages) there is no reason not to use loops in Julia.

Reply via email to