How to create a function in Julia that can accept an array or a scalar as input argument?

Hi, when creating new functions in Julia, do I need to specify the input type of the arguments ? Is this required for speed or only for organization ?

For example, I would like to create a function that takes as input either an array or a scalar number. How would this be possible within the scope of Julia function definitions and code organization ?

I would prefer to specify the input type of my function for easy read of what it expect as input.

function printNumber(x::Array{Number})
    println("value = ", x)
end

inputValue = 10.0
printNumber([inputValue])  # This works

inputValue = 10
printNumber(inputValue)  ## This fails

No, this is not required.
There is a recent thread


where there was a nice explanation about this by @bcmichael

1 Like

Sure, you can do this, although it’s uncommon. Here is a function that takes either a Number or any kind of array-like collection of numbers:

function my_print(x::Union{Number, AbstractArray{<:Number}})
  println("value = ", x)
end

This style is no longer common in Julia because many of us have found that it is clearer and more performant to just write the scalar version of a function and then apply that scalar function to a collection via broadcasting (see https://julialang.org/blog/2017/01/moredots/ ). For example, if you have a function f(x::Number), then you can apply f to an array a by doing f.(a) without having to change anything about the definition of f.

5 Likes

@rdeits, thank you very much for the detailed reply.

The concept of writing a scalar function and then use broadcasting is still not entirely clear to me. For example, the function that I am trying to make it work for both scalar and arrays is below.

Ideally, in the function below the argument tvector would take an array of either floats or integers, whereas tsearch_all could be either an array or a scalar, both also float or integer.

How would I apply the concept of broadcasting in this case ?

function getIndexSpecificTime(tvector,tsearch_all)
    #=
        Get index of a specific time
        Input:
            tvector: Array containing the time
            tsearch_all:: array containg the times to get the indexes

        Output:
            list of index into the tvector array
    =#

    ind_final=zeros(Int64,length(tsearch_all))
    for i=1:length(tsearch_all)
        minv, ind1=findmin( abs.(tvector .- tsearch_all[i]) )
        ind_final[i]=ind1
    end

    return ind_final

end  ### getIndexSpecificTime

tAll = 1:10
tSearch = [5,6]

ind = getIndexSpecificTime(tAll, tSearch)
println.(ind)

Here’s an example:

# getIndexSpecificTime now expects just a single scalar `tsearch`
julia> function getIndexSpecificTime(tvector, tsearch)
         minv, ind1 = findmin(abs.(tvector .- tsearch))
         return ind1
       end
getIndexSpecificTime (generic function with 1 method)

julia> tAll = 1:10
1:10

# We can call it on a scalar, as expected
julia> getIndexSpecificTime(tAll, 2.0)
2

julia> tSearch = [5, 6]
2-element Array{Int64,1}:
 5
 6

# Or we can apply it to a vector `tSearch` via broadcasting.
# Note the use of `Ref()` here: we want to apply `getIndexSpecificTime`
# separately to each element in `tSearch`, but we want to use the *whole*
# `tAll` each time. The `Ref` tells broadcasting to pass the entire `tAll` array
# at every iteration, treating it as if it were an atomic scalar value. 
julia> getIndexSpecificTime.(Ref(tAll), tSearch)
2-element Array{Int64,1}:
 5
 6
2 Likes