Search code examples
functiondataframegroup-bysetjulia

julia lang - how to apply multiple functions to a value


I would like to apply a set of functions to a value and get a set of values as output. I see in help?> groupby (DataFrames package) we can do:

> df |> groupby(:a) |> [sum, length]

> df |> groupby([:a, :b]) |> [sum, length]

but can we do

> [sum, length](groupby([:a, :b]))
 MethodError: objects of type Array{Function,1} are not callable
 square brackets [] for indexing an Array.
 eval_user_input(::Any, ::Base.REPL.REPLBackend) at ./REPL.jl:64
    in macro expansion at ./REPL.jl:95 [inlined]
    in (::Base.REPL.##3#4{Base.REPL.REPLBackend})() at ./event.jl:68

or even

> [sum, length](1:5)

I would expect the output:

[15, 5]

Solution

  • Yes and no. (i.e. yes it's possible, but no, not with that syntax):


    No: The syntax you see with |> and dataframes is not general syntax. It's just how the |> method is defined for dataframes. See its definition in file grouping.jl (line 377) and you'll see it's just a wrapper to another function, and it's defined to either accept a function, or a vector of functions.

    PS: Note that the generic |> which "pipes" an argument into a function, only expects 1-argument functions on the right hand side, and has very little to do with this particular "dataframe-overloaded" method.


    Yes: You can apply a set of functions to a set of inputs in other ways.
    One simple way, e.g. would be via a list comprehension:

    julia> a = [1 2 3;2 3 4];
    julia> [f(a) for f in [sum, length, size]]
    3-element Array{Any,1}:
     15     
      6     
       (2,3)
    

    Or using map:

    julia> map( (x) -> x(a), [sum, length, size])
    

    etc.


    PS: If you're keen to use |> to achieve this, clearly you could also do something like this:

    julia> a |> (x) -> [sum(x), length(x), size(x)]
    

    but presumably that defeats the purpose of what you're trying to do :)