VinodV
June 28, 2024, 8:23am
1
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`

nsajko
June 28, 2024, 8:41am
2
Give a reproducible example.

Qfl3x
June 28, 2024, 8:42am
3
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

VinodV
June 28, 2024, 9:46am
5

ericphanson:

mean(x → x^2, [1,2,3])

```
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?

VinodV
June 28, 2024, 9:53am
7
I should have defined argument as list of dictionaries. Whatever you told is one of the solutions.

1 Like

VinodV
June 28, 2024, 10:49am
9
```
[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.

DNF
June 28, 2024, 6:17pm
12
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