Your requirements are ambiguous, this is one of the problem. For example, if you create following records
dict[(1, 2)] = 1.0
dict[(2, 1)] = 2.0
what should return collect(keys(dict))
? It can be [(1, 2)]
, [(2, 1)]
or [(1, 2), (2, 1)]
depending on the requirements of your original problem. So, there will be no single solution, and therefore one of the way to proceed is to roll out your own implementation.
There are multiply way to do it, but you should be careful, since Dict
has lots of methods and they should be carefully implemented with regards to the problem setup. One way to speed it up is by using Lazy.jl
using Lazy
struct TupleDict{K, V} <: AbstractDict{K, V}
d::Dict{K, V}
end
TupleDict{K, V}() where K where V = TupleDict{K, V}(Dict{K, V}())
TupleDict(kv...) = TupleDict(Dict(kv...)) # careful though, it is not checking for duplicated entries
@forward TupleDict.d Base.iterate, Base.isempty, Base.length, Base.keys, Base.empty!, Base.sizehint!
Base.:haskey(d::TupleDict, k) = haskey(d.d, k) | haskey(d.d, reverse(k))
function Base.:setindex!(d::TupleDict, v, k)
if haskey(d.d, reverse(k))
d.d[reverse(k)] = v
else
d.d[k] = v
end
end
function Base.:getindex(d::TupleDict, k)
haskey(d.d, k) && return d.d[k]
haskey(d.d, reverse(k)) && return d.d[reverse(k)]
throw(KeyError(k))
end
This prototype should be close to what you want
dd = TupleDict{Tuple{Int, Int}, Float64}()
dd[(2, 3)] = 5.0
dd[(3, 2)] # 5.0
dd[(2, 4)] = 1.0
dd[(4, 2)] = 2.0
dd[(2, 4)] # 2.0
collect(keys(dd))
# 2-element Array{Tuple{Int64,Int64},1}:
# (2, 3)
# (2, 4)
If you want other behavior of the keys
you should define setindex!
appropriately.