I'm trying to create a list nested within a dictionary and append values to it. In python, I would have written the following:
samples = {'x' : [1], 'y' : [-1]}
and to append values in a for-loop:
samples['x'].append(new_value)
How can I achieve something equivalent in Julia?
Here it is:
julia> samples = Dict("x" => [1], "y" => [-1])
Dict{String, Vector{Int64}} with 2 entries:
"x" => [1]
"y" => [-1]
julia> push!(samples["x"],4);
julia> samples
Dict{String, Vector{Int64}} with 2 entries:
"x" => [1, 4]
"y" => [-1]
Perhaps in Julia one would consider Symbols as keys instead of Strings so it could be samples = Dict(:x => [1], :y => [-1])
Finally, if you know that the keys are only x and y you would use a NamedTuple:
julia> samples2 = (x = [1], y = [-1])
(x = [1], y = [-1])
julia> typeof(samples2)
NamedTuple{(:x, :y), Tuple{Vector{Int64}, Vector{Int64}}}
julia> push!(samples2.x, 111);
julia> samples2
(x = [1, 111], y = [-1])
Related
I am looking for solution to remove duplicated value in vector which is in dictionary format at Julia.
Here is my dictionary :
x = Dict{AbstractString,Array{Integer,1}}("A" => [1,2,3], "B" => [3,4,5], "C" => [5,6,7])
and below is expected output :
Dict{AbstractString, Vector{Integer}} with 3 entries:
"A" => [1, 2]
"B" => [4]
"C" => [6, 7]
This is a relatively short way to do it (I have not optimized it for full speed to keep the solution short):
julia> using StatsBase
julia> x = Dict{AbstractString,Array{Integer,1}}("A" => [1,2,3], "B" => [3,4,5], "C" => [5,6,7])
Dict{AbstractString, Vector{Integer}} with 3 entries:
"B" => [3, 4, 5]
"A" => [1, 2, 3]
"C" => [5, 6, 7]
julia> dups = [k for (k, v) in countmap(Iterators.flatten(values(x))) if v > 1]
2-element Vector{Int64}:
5
3
julia> foreach(v -> setdiff!(v, dups), values(x))
julia> x
Dict{AbstractString, Vector{Integer}} with 3 entries:
"B" => [4]
"A" => [1, 2]
"C" => [6, 7]
If anything is not clear in the code please comment.
This solution updates your dictionary x in-place as I assumed this is what you wanted.
Or, pedestrian-style
allvalues(x::AbstractDict) = reduce(vcat, collect(values(x)))
function finddups(x::AbstractArray)
dups = Int[]
filter(item -> item in dups ? true : begin
push!(dups, item)
false end, x)
end
x = Dict{AbstractString,Array{Integer,1}}("A" => [1,2,3], "B" => [3,4,5], "C" => [5,6,7])
dups = x |> allvalues |> finddups
foreach(v -> setdiff!(v, dups), values(x))
x
How do I get the size of a Dictionary in julia? size() throws an error.
julia> d = Dict(:x => 1, :y => 2)
julia> size(d)
MethodError: no method matching size(::Dict{Symbol,Int64})
Use length().
julia> d = Dict(:x => 1, :y => 2)
julia> length(d)
2
The reason that size() doesn't work is that size is used to give the dimension of a container. From the docs:
size(A::AbstractArray, [dim])
Return a tuple containing the dimensions of A. Optionally you can specify a dimension to just get the length of that dimension.
and
length(A::AbstractArray)
Return the number of elements in the array, defaults to prod(size(A)).
The point with dictionaries is that they do not really have dimensions. You could of course represent them as one dimensional, but that would ignore the fact that the dictionary values can have "dimension", that are not necessarily uniform. For example, what dimensions should this dictionary then have? Two? Users might incorrectly assume they could access dict[:a][1]:
julia> dict = Dict(:a => 1, :b => [1, 2])
Dict{Symbol,Any} with 2 entries:
:a => 1
:b => [1, 2]
I would like to find a succinct syntax in Julia for indexing a dictionary in a vectorized manner. In R, I would do the following:
dict <- c("a" = 1, "b" = 2)
keys <- c("a", "a", "b", "b", "a")
dict[keys]
In Julia, if I have a dict and keys like this,
dict = Dict(:a => 1, :b => 2)
keys = [:a, :a, :b, :b, :a]
then I can achieve the desired result using a list comprehension:
julia> [dict[key] for key in keys]
5-element Array{Int64,1}:
1
1
2
2
1
Is there a more succinct vectorized syntax, similar to the R syntax?
getindex.(Ref(dict), keys)
You can wrap it in Ref so you don't need to [] it.
Here's a little macro (using the brilliant MacroTools package):
using MacroTools
macro vget(ex)
#capture(ex, dict_.[idxvec_])
:(map(i->$dict[i], $idxvec)) |> esc
end
Then you can:
d = Dict(:a => 1, :b => 2)
ks = [:a, :a, :b, :b, :a]
#vget d.[ks]
I probably wouldn't want to use that in production code, something like your list comprehension, or a simple map: map(i->d[i], ks), is more readable/explicit/standard, but it is fun :D
If you're going to be frequently using the dictionary as a lookup table, then it might be worth creating a closure to use as a lookup function:
make_lookup(dict) = key -> dict[key]
dict = Dict(:a => 1, :b => 2)
lookup = make_lookup(dict)
Then you can use lookup in a vectorized fashion:
julia> keys = [:a, :a, :b, :b, :a];
julia> lookup.(keys)
5-element Array{Int64,1}:
1
1
2
2
1
You can use the vectorized version of getindex:
julia> getindex.([dict], keys)
5-element Array{Int64,1}:
1
1
2
2
1
Note that dict is wrapped in an array so that getindex does not attempt to broadcast over the elements of the dictionary:
julia> getindex.(dict, keys)
ERROR: ArgumentError: broadcasting over dictionaries and `NamedTuple`s is reserved
Stacktrace:
[1] broadcastable(::Dict{Symbol,Int64}) at ./broadcast.jl:615
[2] broadcasted(::Function, ::Dict{Symbol,Int64}, ::Array{Symbol,1}) at ./broadcast.jl:1164
[3] top-level scope at none:0
I want to unpack parameters that are stored in a dictionary. They should be available inside the local scope of a function afterwards. The name should be the same as the key which is a symbol.
macro unpack_dict()
code = :()
for (k,v) in dict
ex = :($k = $v)
code = quote
$code
$ex
end
end
return esc(code)
end
function assign_parameters(dict::Dict{Symbol, T}) where T<:Any
#unpack_dict
return a + b - c
end
dict = Dict(:a => 1,
:b => 5,
:c => 6)
assign_parameters(dict)
However, this code throws:
LoadError: UndefVarError: dict not defined
If I define the dictionary before the macro it works because the dictionary is defined.
Does someone has an idea how to solve this? Using eval() works but is evaluated in the global scope what I want to avoid.
If you want to unpack them then the best method is to simply unpack them directly:
function actual_fun(d)
a = d[:a]
b = d[:b]
c = d[:c]
a+b+c
end
This will be type stable, relatively fast and readable.
You could, for instance, do something like this (I present you two options to avoid direct assignment to a, b, and c variables):
called_fun(d) = helper(;d...)
helper(;kw...) = actual_fun(;values(kw)...)
actual_fun(;a,b,c, kw...) = a+b+c
function called_fun2(d::Dict{T,S}) where {T,S}
actual_fun(;NamedTuple{Tuple(keys(d)), NTuple{length(d), S}}(values(d))...)
end
and now you can write something like:
julia> d = Dict(:a=>1, :b=>2, :c=>3, :d=>4)
Dict{Symbol,Int64} with 4 entries:
:a => 1
:b => 2
:d => 4
:c => 3
julia> called_fun(d)
6
julia> called_fun2(d)
6
But I would not recommend it - it is not type stable and not very readable.
AFACT other possibilities will have similar shortcomings as during compile time Julia knows only types of variables not their values.
EDIT: You can do something like this:
function unpack_dict(dict)
ex = :()
for (k,v) in dict
ex = :($ex; $k = $v)
end
return :(myfun() = ($ex; a+b+c))
end
runner(d) = eval(unpack_dict(d))
and then run:
julia> d = Dict(:a=>1, :b=>2, :c=>3, :d=>4)
Dict{Symbol,Int64} with 4 entries:
:a => 1
:b => 2
:d => 4
:c => 3
julia> runner(d)
myfun (generic function with 1 method)
julia> myfun()
6
but again - I feel this is a bit messy.
In Julia 1.7, you can simply unpack named tuples into the local scope, and you can easily "spread" a dict into a named tuple.
julia> dict = Dict(:a => 1, :b => 5, :c => 6)
Dict{Symbol, Int64} with 3 entries:
:a => 1
:b => 5
:c => 6
julia> (; a, b, c) = (; sort(dict)...)
(a = 1, b = 5, c = 6)
julia> a, b, c
(1, 5, 6)
(The dict keys are sorted so that the named tuple produced is type-stable; if the keys were produced in arbitrary order then this would result in a named tuple with fields in arbitrary order as well.)
I have two dicts and I want to subtract the matching values from the two dicts to generate a third dict.
A = Dict("w" => 2, "x" => 3)
B = Dict("x" => 5, "w" => 7)
# Ideally I could go B .- A and get a dict like
C = Dict("w" => 5, "x" => 2)
# but I get ERROR: ArgumentError: broadcasting over dictionaries and `NamedTuple`s is reserved
One ugly solution is to overload the subtraction operator but I am not keen to overload for a builtin type like dict for fear of breaking other code.
import Base.-
function -(dictA::Dict, dictB::Dict)
keys_of_A = keys(dictA)
subtractions = get.(Ref(dictB), keys_of_A, 0) .- get.(Ref(dictA), keys_of_A, 0)
return Dict(keys_of_A .=> subtractions)
end
Is there a cleaner way to do algebraic operations on matching values from different dicts?
merge provides the result you want.
A = Dict("w" => 2, "x" => 3)
B = Dict("x" => 5, "w" => 7)
C = merge(-, B, A)
Dict{String,Int64} with 2 entries:
"w" => 5
"x" => 2
Note that merge performs a union of the two collections and combines common keys by performing the given operation. So, for example:
W = Dict("w" => 4)
merge(-, B, W)
Dict{String,Int64} with 2 entries:
"w" => 3
"x" => 5