通过迭代字典来定义新变量的有效方法(Julia)

时间:2017-11-14 04:42:55

标签: dictionary julia

考虑Julia中的字典d,它包含数千个键。每个键都是一个符号,每个值都是一个数组。我可以访问与符号:S1相关联的值,并通过

将其分配给变量k1
  

k1 = d [:S1]

现在假设我想通过对特殊键k2, k3, k4, ..., k10重复相同的过程来定义新变量:S1 ... :S10(不是对于字典中的所有键)。最有效的方法是什么?我的印象是这可以使用元编程来解决,但不确定。

3 个答案:

答案 0 :(得分:5)

简单的方法是使用Parameters.jl

using Parameters
d = Dict{Symbol,Any}(:a=>5.0,:b=>2,:c=>"Hi!")
@unpack a, c = d
a == 5.0 #true
c == "Hi!" #true

BTW,这不使用eval。

答案 1 :(得分:3)

如果在编译时都知道特殊键,我建议使用Chris Rackauckas's answer 它不那么邪恶,并且可以创建局部变量。

如果由于某种原因它们仅在运行时被识别, 然后你可以做如下。 (虽然我想要创建变量的变量实际上很奇怪,但在编译时你甚至都不知道这些变量)

@eval是你的朋友*。见the manual @eval $key = $value

或者您可以使用带引号表达式的函数形式eval()eval(:($key = $value))

但请注意,您不能使用它来引入新的局部变量。 eval始终在模块范围内执行。 这是a intentional restriction for performance reasons

julia> d = Dict(k => rand(3) for k in [:a, :b1, :c2, :c1])
Dict{Symbol,Array{Float64,1}} with 4 entries:
  :a  => [0.446723, 0.0853543, 0.476118]
  :b1 => [0.212369, 0.846363, 0.854601]
  :c1 => [0.542332, 0.885369, 0.635742]
  :c2 => [0.118641, 0.987508, 0.578754]

julia> for (k,v) in d
          #create constants for only ones starting with `c`
          if first(string(k)) == c 
              @eval const $k = $v
          end
       end


julia> c2
3-element Array{Float64,1}:
  0.118641
  0.987508
  0.578754

*老实说eval不是你的朋友。 然而,这是唯一一个足以与你一起走在基于运行时值生成代码的黑暗道路上的人。 (@generate只是稍微不那么愿意根据运行时类型生成代码)。 如果您处于这种情况,您绝对必须根据运行时信息生成代码,请考虑您是否在设计上出现了错误,需要进一步提出问题。

答案 2 :(得分:2)

如果你真的想拥有k1,k2,...,k10,......你可以使用比Lyndon更复杂的eval:

for (i,j) in enumerate(d)
       @eval $(Symbol("k$i")) = $j.second
end

警告:eval()使用全局范围,所以即使你在函数k1中使用它... kn也是全局变量。