Looping over variables names properly

I have a few arrays, say x, y, z, and I want to take all of their means and put them into new variables as x_mean = mean(x).
Is there a way to do this in a for loop? Something like

for a in ["x", "y", "z"]
    $a_mean = mean($a)
end

You can do it with @eval:

julia> using Statistics: mean

julia> x, y, z = rand(3), rand(3), rand(3);

julia> for a in [:x, :y, :z]
           @eval $(Symbol(a, "_mean")) = mean($a)
       end

julia> x_mean
0.7142450574816145

Most of the time this is not a great idea though and you would be better off organizing your data differently, but it depends on how you are using it.

6 Likes

You could build something like a Dict that maps variable names to their mean

julia> d = Dict(name=>mean(val) for (name, val) in pairs((; x,y,z)))
Dict{Symbol, Float64} with 3 entries:
  :y => 0.189552
  :z => 0.744915
  :x => 0.551346
3 Likes

It looks like exactly what you do using packages like DataFrames or InMemoryDataset

ulia> df=DataFrame(x=rand(-50:50,10),y=rand(-5:5,10),z=rand(-10:10,10))
10×3 DataFrame
 Row │ x      y      z     
     │ Int64  Int64  Int64
─────┼─────────────────────
   1 │   -35     -3      6
   2 │    41      1     -6
   3 │    34     -3     -7
   4 │    13      2      9
   5 │   -48      5      2
   6 │    43     -2      4
   7 │    38      3      4
   8 │   -12      0     -9
   9 │   -45      3     -1
  10 │     4     -1      8

julia> Tables.columntable(combine(df,Cols(:).=>mean))
(x_mean = [3.3], y_mean = [0.5], z_mean = [1.0])


julia> copy(combine(df,Cols(:).=>mean)[1,:])
(x_mean = 3.3, y_mean = 0.5, z_mean = 1.0)

2 Likes

This is almost never a good idea, and it will only work in global scope. In local scope, this code will start creating global variables.

2 Likes

One could also use named tuples:

x, y, z = rand(3), rand(3), rand(3)
dmean = map(mean, (;x, y, z))

# and then access the results with:
dmean.x, dmean.y, dmean.z

NB:
Learned this from the excellent book in progress: Julia for Data Analysis, by Bogumił Kamiński

3 Likes