I have this JSON:
{"eletrics":{"USA":['trcd', 'moty', 'pily'], "EUROPE" :['bny','ury','try']}, "fuel":{"USA":['tre', 'motr', 'pilow'], "EUROPE" :['bty','tryn','tre']}}
How can I extract all strings in the key==EUROPE
The outuput should be:
europe = ['bny','ury','try','bty','tryn','tre']
in python I would do:
df = df.loc["EUROPE"].explode()
How can I do this in Julia:
Here's one way to do it:
julia> jstr = """
{"eletrics":{"USA":["trcd", "moty", "pily"], "EUROPE" :["bny","ury","try"]}, "fuel":{"USA":["tre", "motr", "pilow"], "EUROPE" :["bty","tryn","tre"]}}
""";
julia> jobj = JSON3.read(jstr)
JSON3.Object{Base.CodeUnits{UInt8, String}, Vector{UInt64}} with 2 entries:
:eletrics => {…
:fuel => {…
julia> europe = reduce(vcat,
(jobj[key][:EUROPE] for key in keys(jobj)));
julia> println(europe)
["bny", "ury", "try", "bty", "tryn", "tre"]
Related
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])
I'm trying to convert a word to an array of one-hot encoded arrays using a simple vocabulary. The dictionary I've constructed is keyed off of characters.
vocab = "abc"
char_id = Dict([ (index, char) for (char, index) in enumerate(vocab) ])
# Dict{Char,Int64} with 3 entries:
# 'a' => 1
# 'c' => 3
# 'b' => 2
function char_to_one_hot(char, char_id, max_length)
one_hot = zeros(max_length)
setindex!(one_hot, 1.0, char_id[char])
end
function word_to_one_hot(word, char_id, max_length)
map((char) -> char_to_one_hot(char, char_id, max_length), split(word, ""))
end
word_to_one_hot(word, char_id, max_length)
Unfortunately, this returns an error because the char_id Dict is uses char keys instead of strings. How can I convert either the dictionary to use string values as keys, or chars to strings so the comparison matches?
ERROR: KeyError: key "a" not found
Stacktrace:
[1] getindex at ./dict.jl:467 [inlined]
[2] char_to_one_hot(::SubString{String}, ::Dict{Char,Int64}, ::Int64) at ./REPL[456]:3
[3] #78 at ./REPL[457]:2 [inlined]
[4] iterate at ./generator.jl:47 [inlined]
[5] _collect(::Array{SubString{String},1}, ::Base.Generator{Array{SubString{String},1},var"#78#79"{Dict{Char,Int64},Int64}}, ::Base.EltypeUnknown, ::Base.HasShape{1}) at ./array.jl:699
[6] collect_similar at ./array.jl:628 [inlined]
[7] map at ./abstractarray.jl:2162 [inlined]
[8] word_to_one_hot(::String, ::Dict{Char,Int64}, ::Int64) at ./REPL[457]:2
[9] top-level scope at REPL[458]:1
A string can already be seen as a collection of characters, so you shouldn't need to split the word.
However, map is specialized in such a way that on strings you can only map functions which return chars. And strings are also treated as scalars by the broadcasting system. This leaves us with a few options: a simple for loop or maybe a generator/comprehension.
I think in this case I'd go with the comprehension:
function char_to_one_hot(char, char_id, max_length)
one_hot = zeros(max_length)
setindex!(one_hot, 1.0, char_id[char])
end
function word_to_one_hot(word, char_id, max_length)
[char_to_one_hot(char, char_id, max_length) for char in word]
end
which I think gives what you'd expect:
julia> vocab = "abc"
"abc"
julia> char_id = Dict([ (index, char) for (char, index) in enumerate(vocab) ])
Dict{Char,Int64} with 3 entries:
'a' => 1
'c' => 3
'b' => 2
julia> word_to_one_hot("acb", char_id, 5)
3-element Array{Array{Float64,1},1}:
[1.0, 0.0, 0.0, 0.0, 0.0]
[0.0, 0.0, 1.0, 0.0, 0.0]
[0.0, 1.0, 0.0, 0.0, 0.0]
If you still want to convert between 1-character strings and characters, you can do it this way:
julia> str="a"; first(str)
'a': ASCII/Unicode U+0061 (category Ll: Letter, lowercase)
julia> chr='a'; string(chr)
"a"
To convert length 1 string to char, reference the string's first char with [1].
To convert char to string, use string().
julia> s = "c"
"c"
julia> s[1]
'c': ASCII/Unicode U+0063 (category Ll: Letter, lowercase)
julia> string(s)
"c"
I have some dictionary that already exists. I want to add a new key-value pair, but I do not want to create a new dictionary from scratch.
How can I add a new key-value pair to an existing dictionary in Julia?
Julia uses the common dict[key] = value syntax for setting a key-value pair:
julia> dict = Dict(1 => "one")
Dict{Int64,String} with 1 entry:
1 => "one"
julia> dict[2] = "two"
"two"
julia> dict
Dict{Int64,String} with 2 entries:
2 => "two"
1 => "one"
The same syntax will override a key-value pair if the key already exists:
julia> dict
Dict{Int64,String} with 2 entries:
2 => "two"
1 => "one"
julia> dict[1] = "foo"
"foo"
julia> dict
Dict{Int64,String} with 2 entries:
2 => "two"
1 => "foo"
dict[key] = value is syntax for a setindex! call. Although not as common, you can call setindex! directly:
julia> dict = Dict(1 => "one")
Dict{Int64,String} with 1 entry:
1 => "one"
julia> setindex!(dict, "two", 2)
Dict{Int64,String} with 2 entries:
2 => "two"
1 => "one"
I have strings with annotated attributes. You can think of them as XML-document strings, but with custom syntax of annotation.
Attributes in a string are encoded as follows:
#<atr_name>=<num_of_chars>:<atr_value>\n
where
<atr_name> is a name of the attribute
<atr_value> is a value of the attribute
<num_of_chars> is a character length of the <atr_value>
That is attribute name is prefixed with # and postfixed with =, then followed by number that indicates number of characters in the value of the attribute, then followed by :, then followed by the attribute's value itself, and then followed by with newline character \n
Here is one example:
julia> string_with_attributes = """
some text
...
#name=6:Azamat
...
#year=4:2016
...
some other text
"""
Now I want to write a function or a macro that would allow me to call as:
julia> string_with_attributes["name"]
"Azamat"
julia> string_with_attributes["year"]
"2016"
julia>
Any ideas on how to do this?
Following #Gnimuc answer, you could make your own string macro AKA non standard string literal if that suit your needs, ie:
julia> function attr_str(s::S)::Dict{S, S} where {S <: AbstractString}
d = Dict{S, S}()
for i in eachmatch(r"(?<=#)\b.*(?==).*(?=\n)", s)
push!(d, match(r".*(?==)", i.match).match => match(r"(?<=:).*", i.match).match)
end
push!(d, "string" => s)
return d
end
attr_str (generic function with 1 method)
julia> macro attr_str(s::AbstractString)
:(attr_str($s))
end
#attr_str (macro with 1 method)
julia> attr"""
some text
dgdfg:dgdf=ert
#name=6:Azamat
all34)%(*)#:DG:Ko_=ddhaogj;ldg
#year=4:2016
#dkgjdlkdag:dfgdfgd
some other text
"""
Dict{String,String} with 3 entries:
"name" => "Azamat"
"string" => "some text\ndgdfg:dgdf=ert\n#name=6:Azamat\nall34)%(*)#:DG:Ko_=ddhaogj;ldg\n#year=4:2016\n#dkgjdlkdag:dfgdfgd\nsome other text\n"
"year" => "2016"
julia>
seems like a job for regex:
julia> string_with_attributes = """
some text
dgdfg:dgdf=ert
#name=6:Azamat
all34)%(*)#:DG:Ko_=ddhaogj;ldg
#year=4:2016
#dkgjdlkdag:dfgdfgd
some other text
"""
"some text\ndgdfg:dgdf=ert\n#name=6:Azamat\nall34)%(*)#:DG:Ko_=ddhaogj;ldg\n#year=4:2016\n#dkgjdlkdag:dfgdfgd\nsome other text\n"
julia> s = Dict()
Dict{Any,Any} with 0 entries
julia> for i in eachmatch(r"(?<=#)\b.*(?==).*(?=\n)", string_with_attributes)
push!(s, match(r".*(?==)", i.match).match => match(r"(?<=:).*", i.match).match)
end
julia> s
Dict{Any,Any} with 2 entries:
"name" => "Azamat"
"year" => "2016"
So, turns out what I needed was to extend the Base.getindex method from Indexing interface.
Here is the solution that I ended up doing:
julia>
function Base.getindex(object::S, attribute::AbstractString) where {S <: AbstractString}
m = match( Regex("#$(attribute)=(\\d*):(.*)\n"), object )
(typeof(m) == Void) && error("$(object) has no attribute with the name $(attribute)")
return m.captures[end]::SubString{S}
end
julia> string_with_attributes = """
some text
dgdfg:dgdf=ert
#name=6:Azamat
all34)%(*)#:DG:Ko_=ddhaogj;ldg
#year=4:2016
#dkgjdlkdag:dfgdfgd
some other text
"""
julia> string_with_attributes["name"]
"Azamat"
julia> string_with_attributes["year"]
"2016"
When I tried to do:
d = {1:2, 3:10, 6:300, 2:1, 4:5}
I get the error:
syntax: { } vector syntax is discontinued
How to initialize a dictionary in Julia?
The {} syntax has been deprecated in julia for a while now. The way to construct a dict now is:
Given a single iterable argument, constructs a Dict whose key-value pairs are taken from 2-tuples (key,value) generated by the argument.
julia> Dict([("A", 1), ("B", 2)])
Dict{String,Int64} with 2 entries:
"B" => 2
"A" => 1
Alternatively, a sequence of pair arguments may be passed.
julia> Dict("A"=>1, "B"=>2)
Dict{String,Int64} with 2 entries:
"B" => 2
"A" => 1
(as quoted from the documentation, which can be obtained by pressing ? in the terminal to access the "help" mode, and then type Dict)