有没有办法强制字典保持不变?
我有一个函数可以读取参数文件(并忽略注释)并将其存储在dict中:
function getparameters(filename::AbstractString)
f = open(filename,"r")
dict = Dict{AbstractString, AbstractString}()
for ln in eachline(f)
m = match(r"^\s*(?P<key>\w+)\s+(?P<value>[\w+-.]+)", ln)
if m != nothing
dict[m[:key]] = m[:value]
end
end
close(f)
return dict
end
这很好用。由于我有很多参数,我将最终在不同的地方使用,我的想法是让这个词是全局的。众所周知,全局变量并不那么好,所以我想确保dict及其成员是不可变的。
这是一个好方法吗?我该怎么做?我必须这样做吗?
Bonus answerable stuff:)
我的代码还可以吗? (这是我用julia做的第一件事,来自c / c ++和python我倾向于以不同的方式做事。)我是否需要检查文件是否实际打开?我读的文件是“julia”吗?我也可以readall
然后使用eachmatch
。我没有看到“正确的方法”(如在python中)。
答案 0 :(得分:4)
为什么不使用ImmutableDict?它在基础中定义但未导出。您使用如下:
julia> id = Base.ImmutableDict("key1"=>1)
Base.ImmutableDict{String,Int64} with 1 entry:
"key1" => 1
julia> id["key1"]
1
julia> id["key1"] = 2
ERROR: MethodError: no method matching setindex!(::Base.ImmutableDict{String,Int64}, ::Int64, ::String)
in eval(::Module, ::Any) at .\boot.jl:234
in macro expansion at .\REPL.jl:92 [inlined]
in (::Base.REPL.##1#2{Base.REPL.REPLBackend})() at .\event.jl:46
julia> id2 = Base.ImmutableDict(id,"key2"=>2)
Base.ImmutableDict{String,Int64} with 2 entries:
"key2" => 2
"key1" => 1
julia> id.value
1
你可能想要定义一个构造函数,它接受一对(或键和值)数组并使用该算法来定义整个dict(这是唯一的方法,请参见底部的注释)。 / p>
只是一个补充说明,实际的内部表示是每个字典只包含一个键值对和一个字典。 get方法只是遍历字典,检查它是否具有正确的值。这样做的原因是因为数组是可变的:如果你使用可变字段进行了不可变类型的天真构造,那么该字段仍然是可变的,因此id["key1"]=2
不起作用,id.keys[1]=2
会。他们通过不使用可变类型来保存值(因此仅保存单个值)然后还持有不可变的dict来解决这个问题。如果你想直接在数组上做这个工作,你可以使用类似ImmutableArrays.jl之类的东西,但我不认为你会获得性能优势,因为你在检查时仍需要遍历数组键...
答案 1 :(得分:3)
<强> REVISION 强>
感谢Chris Rackauckas指出我之前的回复中的错误。我将把它留在下面,作为不起作用的例证。但是,Chris是对的,当你将字典输入函数时,const
声明实际上似乎并没有提高性能。 因此,请参阅Chris对此问题的最佳解决方案的回答:
D1 = [i => sind(i) for i = 0.0:5:3600];
const D2 = [i => sind(i) for i = 0.0:5:3600];
function test(D)
for jdx = 1:1000
# D[2] = 2
for idx = 0.0:5:3600
a = D[idx]
end
end
end
## Times given after an initial run to allow for compiling
@time test(D1); # 0.017789 seconds (4 allocations: 160 bytes)
@time test(D2); # 0.015075 seconds (4 allocations: 160 bytes)
旧回复
如果您希望字典为常量,可以使用:
const MyDict = getparameters( .. )
更新请记住,虽然在基础朱莉娅中,与其他语言不同,并不是无法重新定义常量,而是仅仅是当您收到警告时这样做。
julia> const a = 2
2
julia> a = 3
WARNING: redefining constant a
3
julia> a
3
在向字典添加新的key-val对时,没有获得常量重定义警告,这很奇怪。但是,你仍然认为通过将其声明为常数来提升性能:
D1 = [i => sind(i) for i = 0.0:5:3600];
const D2 = [i => sind(i) for i = 0.0:5:3600];
function test1()
for jdx = 1:1000
for idx = 0.0:5:3600
a = D1[idx]
end
end
end
function test2()
for jdx = 1:1000
for idx = 0.0:5:3600
a = D2[idx]
end
end
end
## Times given after an initial run to allow for compiling
@time test1(); # 0.049204 seconds (1.44 M allocations: 22.003 MB, 5.64% gc time)
@time test2(); # 0.013657 seconds (4 allocations: 160 bytes)
答案 2 :(得分:3)
首先,我是朱莉娅的新手(我已经使用/学习它仅两周了)。所以除非经过其他人的验证,否则不要对我要说的内容充满信心。
字典数据结构Dict
在这里定义
julia/base/dict.jl
该文件中还有一个名为ImmutableDict
的数据结构。但是,由于const
变量实际上不是const,为什么不可变字典是不可变的?
评论指出:
ImmutableDict是一个实现为不可变链表的字典, 这对于在许多单独插入上构建的小字典是最佳的 请注意,虽然可以部分覆盖和隐藏值,但无法删除值 通过插入具有相同键的新值
因此,让我们将您想要定义的内容称为字典UnmodifiableDict
以避免混淆。这样的对象可能有
Dict
类似的数据结构。Dict
作为输入来填充其数据结构。setindex!
的!
结尾并因此修改数据的所有其他函数的情况。据我所知,只有抽象类型的子类型才有可能。因此,您无法将UnmodifiableDict
作为Dict
的子类型,只能重新定义setindex!
不幸的是,这是运行时类型而非编译时类型的必要限制。没有一些限制,你不可能有这么好的表现。
底线:
我看到的唯一解决方案是复制粘贴Dict
类型的代码及其功能,将Dict
替换为UnmodifiableDict
,并修改以{{1}结尾的函数如果被调用则引发异常。
您可能还想查看这些主题。
答案 3 :(得分:2)
要添加现有答案,如果您想要不变性并希望获得改变和扩展字典的高性能(但仍然持久)操作,请查看FunctionalCollections.jl&#39; s PersistentHashMap
类型。
如果您希望最大限度地提高性能并最大限度地利用不变性,并且您不打算在字典上进行任何操作,请考虑实施基于perfect hash function的字典。实际上,如果你的字典是编译时常量,那么甚至可以提前计算它们(使用元编程)并预编译。