# Creating function that broadcast function over multiple keyword arguments

**URL:** https://discourse.julialang.org/t/creating-function-that-broadcast-function-over-multiple-keyword-arguments/55491
**Category:** Performance
**Created:** [February 17, 2021, 10:29pm UTC](https://discourse.julialang.org/t/creating-function-that-broadcast-function-over-multiple-keyword-arguments/55491 "2021-02-17T22:29:31Z")
**Posts on this page:** 8
**Page:** 1

<div class="post-metadata">

### Author: ![matnbo](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/matnbo/32/220166_2.png) [@matnbo](https://discourse.julialang.org/u/matnbo)
#### Post date: [February 17, 2021, 10:29pm UTC](https://discourse.julialang.org/t/creating-function-that-broadcast-function-over-multiple-keyword-arguments/55491/1 "2021-02-17T22:29:31Z")

</div>

Dear all

I come from the R community, and try to switch to Julia )  
Assume I have a function f1 (fictive function below)

> f1 = function(x, y ; a = 1.5, b = 5)  
> coef = a \* sum(x’y) + b  
> (coef = coef, mod = 1)  
> end

where x, y are vectors, e.g.

> x = [1, 10, -2] ; y = [.5, 7, 22.3] ;

and that I want to replicate this function over vectors (instead of single elements)  
of parameters a and b, for instance

> a = [1, 2] ; b = [.5, -.5] ;

Using map, I can do

> map((a, b) → f1(x, y ; a = a, b = b), a, b)

or with another syntax  
([Julia: Passing keyword arguments to function through the map() function - Stack Overflow](https://stackoverflow.com/questions/38906788/julia-passing-keyword-arguments-to-function-through-the-map-function))

> map(a, b) do a, b  
> f1(x, y ; a = a, b = b)  
> end

I can also build the following meta function ‘metaf’ (using the second syntax  
since in real I have successive steps in the map)

> metaf = function(x, y, fun ; a, b)  
> map(a, b) do a, b  
> fun(x, y ; a = a, b = b)  
> end  
> end

> metaf(x, y, f1 ; a = a, b = b)

What I would like is such a metaf function but being **generic** for any function ‘fun’ that can have  
its own arguments (different from ‘a’ and ‘b’ of function ‘f1’ above).  
.  
Something like

> metaf(x, y, fun = f2 ; gamma, alpha, theta)  
> metaf(x, y, fun = OtherFun ; C)

etc.

Is it possible to do this with map in the previous metaf function?

Or may be map is not the efficient way?

I tried to incorporate things like ‘args…’ in metaf but without success

Thanks for any ideas

---

<div class="post-metadata">

### Author: ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)
#### Post date: [February 18, 2021, 12:05am UTC](https://discourse.julialang.org/t/creating-function-that-broadcast-function-over-multiple-keyword-arguments/55491/3 "2021-02-18T00:05:26Z")

</div>

I think you can do

```julia
f1.(Ref(x),Ref(y),a=a,b=b) # note the dot

```

In which case the function call will be broadcasted on a and b only

Edit: no, it does not work for keyword parameters.

Something on these lines could work (sorry I am not really able to test anything now)

```julia
f(x,args...) = args[1][1]*x .+ args[2][1]

x = [1, 2]
a = [2, 4, 6]
b = [1, 1, 2]

@show f(x,1,2)

@show f.(Ref(x),a,b)

```

---

<div class="post-metadata">

### Author: ![FPGro](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/fpgro/32/20822_2.png) [@FPGro](https://discourse.julialang.org/u/FPGro)
#### Post date: [February 18, 2021, 12:35am UTC](https://discourse.julialang.org/t/creating-function-that-broadcast-function-over-multiple-keyword-arguments/55491/4 "2021-02-18T00:35:48Z")

</div>

Quick question:

```julia
julia> map(+, [1,2], [3,4,5,6,7])
2-element Vector{Int64}:
 4
 6

```

is this what you intend with `a` and `b`, applying `fun` on direct pairs of values, or do you want to apply `fun` on every combination of elements in `a` and `b`?

Edit: both are totally possible but neither looks particularly elegant. The problem is, that keyword arguments get passed as NamedTuples (or a pairs view thereof) and are also expected in this form by fun (NamedTuple or Dict{Symbol,\_}). So you essentially want to iterate the content of each element of the named tuple while preserving the name. Not too hard but looks unwieldly:

```julia
transform_kwargs(; kwargs...) = [map(x->Pair(arg.first, x), arg.second) for arg in kwargs]
transform_kwargs(kwargs) = [map(x->Pair(arg.first, x), arg.second) for arg in kwargs]

```

```julia
julia> transform_kwargs(a = [1,2], b = [:x, :y, :z], c = 2)
3-element Vector{Any}:
     [:a => 1, :a => 2]
     [:b => :x, :b => :y, :b => :z]
 :c => 2
# note that this breaks down for non-iterable arguments like transform_kwargs(say = :nooooo)
# so probably not the most reasonable implementation, sorry ^^

```

(please correct me if there’s a function for that already, couldn’t think of one)

Your `metafun` gets easy then (solved for all pairs of arguments here):

```julia
function metaf(x, y, fun; kwargs...)
    combos = Iterators.product(transform_kwargs(kwargs)...)
    return [fun(x, y; keywords...) for keywords in combos]
end

```

```julia
julia> metaf([1,2,3], [4,5,6], 
(x,y;alpha, beta, theta)->(theta .* y ./ exp.(alpha .+ beta .* x)); 
alpha = [-1, 0, 1], beta = collect(1.:0.1:2.), theta = [1.] )
3×11×1 Array{Vector{Float64}, 3}:
[:, :, 1] =
 [4.0, 1.8394, 0.812012] [3.61935, 1.50597, 0.601553] … [1.47152, 0.248935, 0.0404277]
 [1.47152, 0.676676, 0.298722] [1.33148, 0.554016, 0.221299] [0.541341, 0.0915782, 0.0148725]
 [0.541341, 0.248935, 0.109894] [0.489826, 0.203811, 0.0814114] [0.199148, 0.0336897, 0.00547129]

```

But this looks rather opaque, so you can probably come up with a clearer and more explicit solution.

Editedit: if you put `fun` as a first argument to `metaf`, this enables do-block syntax which makes it a lot more readable.

---

<div class="post-metadata">

### Author: ![matnbo](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/matnbo/32/220166_2.png) [@matnbo](https://discourse.julialang.org/u/matnbo)
#### Post date: [February 18, 2021, 8:50am UTC](https://discourse.julialang.org/t/creating-function-that-broadcast-function-over-multiple-keyword-arguments/55491/5 "2021-02-18T08:50:03Z")

</div>

Thanks for quoting me this syntax wuth f. and @show… I will study it.  
But I think

> [@lmiq](#):
>
> `args[1][1]*x .+ args[2][1]`

is a constraint to me, since here it requires to know that the function f has two arguments, while f1, f2 etc. can have different numbers of arguments and I would like to automatize. Thanks anyway

---

<div class="post-metadata">

### Author: ![matnbo](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/matnbo/32/220166_2.png) [@matnbo](https://discourse.julialang.org/u/matnbo)
#### Post date: [February 18, 2021, 8:53am UTC](https://discourse.julialang.org/t/creating-function-that-broadcast-function-over-multiple-keyword-arguments/55491/6 "2021-02-18T08:53:31Z")

</div>

> [@FPGro](#):
>
> is this what you intend with `a` and `b` , applying `fun` on direct pairs of values

Yes, direct pairs

Many thanks for all your powerfull code. I will work on it in more details and if needed will come back to you

---

<div class="post-metadata">

### Author: ![sijo](https://avatars.discourse-cdn.com/v4/letter/s/da6949/32.png) [@sijo](https://discourse.julialang.org/u/sijo)
#### Post date: [February 18, 2021, 9:38am UTC](https://discourse.julialang.org/t/creating-function-that-broadcast-function-over-multiple-keyword-arguments/55491/7 "2021-02-18T09:38:59Z")

</div>

Another solution:

```julia
function metaf(x, y, f; args...)
    names = [a.first for a in args]
    values = [a.second for a in args]
    map(values...) do v...
        f(x, y; Pair.(names, v)...)
    end
end

```

or even shorter:

```julia
function metaf(x, y, f; args...)
    map(values(args)...) do v...
        f(x, y; Pair.(keys(args), v)...)
    end
end

```

Example:

```julia
x = 1;
y = 2;
a = [1,2,3];
b = [4,5,6];

function myf(x, y; a, b)
    coef = a * sum(x'y) + b
    (coef = coef, mod = 1)
end

julia> metaf(x, y, myf; a, b)
3-element Vector{NamedTuple{(:coef, :mod), Tuple{Int64, Int64}}}:
 (coef = 6, mod = 1)
 (coef = 9, mod = 1)
 (coef = 12, mod = 1)

```

---

<div class="post-metadata">

### Author: ![matnbo](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/matnbo/32/220166_2.png) [@matnbo](https://discourse.julialang.org/u/matnbo)
#### Post date: [February 18, 2021, 9:48am UTC](https://discourse.julialang.org/t/creating-function-that-broadcast-function-over-multiple-keyword-arguments/55491/8 "2021-02-18T09:48:23Z")

</div>

This is amazing! (@sudete) It seems being exactly what I had in mind when I posted my questions. Many thanks!

. also thanks again to others for the other ideas )

---

<div class="post-metadata">

### Author: ![FPGro](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/fpgro/32/20822_2.png) [@FPGro](https://discourse.julialang.org/u/FPGro)
#### Post date: [February 18, 2021, 10:15am UTC](https://discourse.julialang.org/t/creating-function-that-broadcast-function-over-multiple-keyword-arguments/55491/9 "2021-02-18T10:15:11Z")

</div>

@sijo well done, does the right thing and is much prettier than my version!
