# Map and reduce with multiple parameters

The following Python-to-Julia exercise is taken from
https://maryrosecook.com/blog/post/a-practical-introduction-to-functional-programming
Generally I am having difficulties with map and reduce when dealing with multiple parameters.

``````function assoc(_d, key, value)
d = deepcopy(_d)
d[key] = value
return d
end
end
function strip_punctuation_from_name(band)
return assoc(band, "name", replace(band["name"], "."=>""))
end
function capitalize_names(band)
return assoc(band, "name", titlecase(band["name"]))
end
strip_punctuation_from_name,
capitalize_names]
bands = [Dict("name"=>"sunset rubdown", "country"=>"UK", "active"=>false),
Dict("name"=>"women", "country"=>"Germany", "active"=>false),
Dict("name"=>"a silver mt. zion", "country"=>"Spain", "active"=>true)]

# Exercise 4. Try and write the pipeline_each function. Think about the order of operations.
# The bands in the array are passed, one band at a time, to the first transformation function.
# The bands in the resulting array are passed, one band at a time, to the second transformation function.
# And so forth.
# A solution:
#=
def pipeline_each(data, fns):
return reduce(lambda a, x: map(x, a),
fns,
data)
=#
function pipeline_each(data, fns)
reduce(a,x -> map(x,a), fns, data) # not operational
#mapreduce ?
end
pipeline_each(bands, ops)
``````

Anonymous functions with multiple arguments need brackets around their arguments, like `(a, x) -> map(x, a)`. Hope that helps!

https://docs.julialang.org/en/v1/manual/functions/#man-anonymous-functions

I am not familiar with Python.
There are a lot of (implicit) questions here:

1. about map/reduce an multiple arguments
2. how to translate the Python code to Julia
3. how to solve the example you linked in a Julian way

some food for thought on map/reduce:

``````a = 1:5
b = 2:6

?map()
map((i,j)->i^j,a,b)
?reduce()
reduce(+,map((i,j)->i^j,a,b))
?mapreduce()
z = zip(a,b)
mapreduce(x->x^x,+,z)
mapreduce((i,j)->i^j,+,a,b)

#you can also use global variables in map
sum(map(i->a[i]^b[i],1:length(a)))
``````

Regarding pipelines, see GitHub - oxinabox/Pipe.jl: An enhancement to julia piping syntax

1 Like

Nice way to explore functions!
I am not sure if any of these covers my use case though.

As a simpler MWE, take the following problem with the same structure:

``````julia> x = [1,2,3]
3-element Vector{Int64}:
1
2
3

julia> funs = [sin,cos,tan]
3-element Vector{Function}:
sin (generic function with 13 methods)
cos (generic function with 13 methods)
tan (generic function with 12 methods)

julia> funs.(funs.(funs.(x)))
3-element Vector{Float64}:
0.786357394978223
0.7053391147354299
1.523873017405459
``````

How to express this operation for an arbitrary array funs using map or reduce?

I think you are looking for function composition: `?∘`

That’s all well, but no. (But yes in the end, see your solution below)
The context from the original Python article is “functional programming”, so a stateless function which accepts arbitrary inputs is sought.
The Python article uses a combination of map and reduce. The earlier examples and exercises were an almost 1:1 translation. So I guess that’s possible here.

Maybe this

``````julia> x = [1, 2, 3]
3-element Vector{Int64}:
1
2
3

julia> funs = [sin, cos, tan]
3-element Vector{Function}:
sin (generic function with 13 methods)
cos (generic function with 13 methods)
tan (generic function with 12 methods)

julia> reduce((val, fun) -> map(fun, val), funs, init=x)
3-element Vector{Float64}:
0.786357394978223
0.7053391147354299
1.523873017405459

julia> funs.(funs.(funs.(x)))
3-element Vector{Float64}:
0.786357394978223
0.7053391147354299
1.523873017405459
``````
1 Like

Simpler:
`reduce(∘, [tan, cos, sin]).([1,2,3])`

2 Likes

Wow, thank you so much for the two solutions
(one more Python- the other more Julia-like)
and to everyone who helped - great community!

1 Like