What would be an equivalent julia code

I have a piece of code in python

def average_by(lst, fn = lambda x: x):
  return sum(map(fn, lst), 0.0) / len(lst)

average_by([{ 'n': 4 }, { 'n': 2 }, { 'n': 8 }, { 'n': 6 }], lambda x: x['n'])
# 5.0

What would be the equivalent julia code?

function average_by(lst; fn = x -> x)
  return sum(map(fn, lst)) / length(lst)
end
 a = Dict("1" => 2,"2" => 3)
 average_by(a,fn = x -> x["n"])

Error : ERROR: map is not defined on dictionaries

Give a reproducible example.

It works though; Make sure lst is a Vector (List) of dictionaries, and not a dictionary itself (Same as the Python code):

julia> lst = [Dict("n" => 4), Dict("n" => 2), Dict("n" => 8), Dict("n" => 6)]
4-element Vector{Dict{String, Int64}}:
 Dict("n" => 4)
 Dict("n" => 2)
 Dict("n" => 8)
 Dict("n" => 6)

julia> function average_by(lst; fn = x -> x)
         return sum(map(fn, lst)) / length(lst)
       end
average_by (generic function with 1 method)

julia> average_by(lst; fn = x -> x["n"])
5.0

2 Likes

You could also try mean(f, itr) (available with using Statistics).

For example, mean(x -> x^2, [1,2,3]).

1 Like

julia>  a = Dict("1" => 2,"2" => 3)                                                 
Dict{String, Int64} with 2 entries:                                                 
  "1" => 2                                                                          
  "2" => 3                                                                          
                                                                                    
julia> mean(x -> x["n"], a)                                                         
ERROR: MethodError: no method matching getindex(::Pair{String, Int64}, ::String)
julia> st = [Dict("n" => 4), Dict("n" => 2), Dict("n" => 8), Dict("n" => 6)]       
4-element Vector{Dict{String, Int64}}:                                             
 Dict("n" => 4)                                                                    
 Dict("n" => 2)                                                                    
 Dict("n" => 8)                                                                    
 Dict("n" => 6)                                                                    
                                                                                   
julia>  mean(x -> x["n"], st)                                                      
5.0

are those the results you expected, or is there something you want to be able to do but are having trouble?

I should have defined argument as list of dictionaries. Whatever you told is one of the solutions.

1 Like

try

average_by(values(a))
[quote="Qfl3x, post:3, topic:116341"]
`lst = [Dict("n" => 4), Dict("n" => 2), Dict("n" => 8), Dict("n" => 6)]`
[/quote]

julia> a = [Dict("n" => 4), Dict("n" => 2), Dict("n" => 8), Dict("n" => 6)]
4-element Vector{Dict{String, Int64}}:
 Dict("n" => 4)
 Dict("n" => 2)
 Dict("n" => 8)
 Dict("n" => 6)

julia> average_by(values(a))
ERROR: MethodError: no method matching +(::Dict{String, Int64}, ::Dict{String, Int64})
julia> a = Dict("1" => 2,"2" => 3)
Dict{String, Int64} with 2 entries:
  "1" => 2
  "2" => 3

julia> average_by(values(a))
2.5

Your code already works, but I would use Iterators.map to handle arbitrary iterables.
Another issue is what should happen if your iterator is empty. The default implementation errors, which is probably the most reasonable thing to do. But you may want to return NaN instead.

This will first map over the vector, creating an unnecessary intermediate collection (particularly unnecessary for the default map function). It’s better to use the sum function with the mapping argument, like this:

sum(fn, lst) / length(lst) 

As for the function signature, two points

  • fn isn’t a kwarg in the Python code, so the semicolon should be a comma.
  • There’s actually a function in Base that is equal to x -> x, called identity. It doesn’t make any difference here, but it’s common to use it as a ‘default function’.
3 Likes