diff --git a/src/interface.jl b/src/interface.jl index ba15b2f..a7b45eb 100644 --- a/src/interface.jl +++ b/src/interface.jl @@ -6,11 +6,11 @@ export noNegative!, randomWithProb, randomChoiceWithProb, findIndex, limitvalue, matMul_3Dto4D_batchwise, isNotEqual, linearToCartesian, vectorMax, findMax, multiply_last, multiplyRandomElements, replaceElements, replaceElements!, isBetween, isLess, allTrue, getStringBetweenCharacters, JSON3read_stringKey, mkDictPath!, - getDictPath, detectKeywordVariation, textToDict + getDictPath, detectKeywordVariation, textToDict, dictify, ordereddictify using JSON, DataStructures, Distributions, Random, Dates, UUIDs, DataFrames, CSV using ..util, ..communication -#[WORKING] update code to use JSON + # ---------------------------------------------- 100 --------------------------------------------- # noNegative!(a::AbstractVector) = replace!(x -> x < 0 ? 0 : x, a) @@ -148,7 +148,7 @@ function findMax(collection::AbstractVector) return maxValue, maxIndex, matchPosition end - +# ---------------------------------------------- 100 --------------------------------------------- # """ read_textfile_by_index(folder_path::String, read_file_number::Integer=1) @@ -185,8 +185,94 @@ function read_textfile_by_index(folder_path::String, read_file_number::Integer=1 end -# ---------------------------------------------- 100 --------------------------------------------- # +""" Recursively convert dictionary-like variable (e.g. JSON.Object) into a dictionary. + +# What it does + - Walks any nested structure composed of `AbstractDict` (e.g., `JSON.Object`, + `Dict`, `OrderedDict`) and `AbstractArray` and produces a new tree where + every dictionary-like node is a plain `Dict` and every array-like node is a + `Vector{Any}`. Scalar values (numbers, strings, booleans, `nothing`, etc.) + are returned unchanged. + - Does **not** mutate the input; it always allocates new containers. + +# Arguments +- `x` + Any Julia value. If `x` is an `AbstractDict` it will be converted to a `Dict`; + if it is an `AbstractArray` its elements will be processed recursively. + +# Keyword Arguments +- `stringkey::Bool=false` + If `true`, every dictionary key is converted to `String` via `string(k)`. + If `false`, original key objects are preserved (useful when keys are already + `String`, `Symbol`, or other types you want to keep). + +# Return +- A newly allocated nested structure composed of `Dict{Any,Any}` and + `Vector{Any}` that mirrors the input shape but uses plain Julia containers. + +# Notes +- The function treats any `AbstractDict` as a mapping source, so it works with + `JSON.Object`, `Dict`, `OrderedDict`, etc. +- Arrays are returned as `Vector{Any}` with their elements processed + recursively. + +# Examples +```jldoctest +julia> using JSON +julia> d = Dict( + "a" => 4, + "b" => 6, + "c" => Dict( + "d"=>7, + :e=>Dict( + "f"=>"hey", + "g"=>Dict( + "world"=>[1, "2", 3, Dict(:dd=>4.7)] + ) + ) + ) + ) + +julia jsonstring = JSON.json(d) +julia> A1 = JSON.parse(jsonstring) # A1 type is JSON.Object +julia> A2 = dictify(A1) +Dict{Any,Any} with 3 entries: + "a" => 4 + "b" => 6 + "c" => Dict("d"=>7, "e"=>Dict("f"=>"hey", "g"=>Dict("world"=>[1, "2", 3, 4.7]))) + +julia> A3 = dictify(A1; stringkey=false) # preserves original key objects +julia> B1 = dictify(d; stringkey=true) # convert all keys in to string +Dict{Any, Any} with 3 entries: + "c" => Dict{Any, Any}("e"=>Dict{Any, Any}("f"=>"hey", "g"=>Dict{Any, Any}("world"=>Any[1, "2", 3, Dict{Any, Any}("dd"=>4.7)])), "d"=>7) + "b" => 6 + "a" => 4 +``` +""" +function dictify(x; stringkey::Bool=false) + # Dict-like objects + if x isa AbstractDict + # choose output key type container (String keys when requested) + out = Dict{Any,Any}() + for (k,v) in x + newk = stringkey ? string(k) : k + out[newk] = dictify(v; stringkey=stringkey) + end + return out + # Arrays / vectors: map elements recursively and return a Vector{Any} + elseif x isa AbstractArray + return [dictify(element; stringkey=stringkey) for element in x] + # everything else: return as-is (primitives, numbers, strings, etc.) + else + return x + end +end + + + + +# ---------------------------------------------- 100 --------------------------------------------- # """ Array_to_JSON_str(data::AbstractArray) @@ -204,27 +290,8 @@ function Array_to_JSON_str(data::AbstractArray) return jsonStr end - # ---------------------------------------------- 100 --------------------------------------------- # -""" JSON3_str_to_Array(json3_str::String) - - decode JSON3 String to Array - - # Example - - json3_str = {"Array":[1.23,9987.1,-0.0027,4.7889,-123.07,-6.75],"size":[3,2]} - a = JSON3_str_to_Array(json3_str) - - a = [1.23 4.7889; 9987.1 -123.07; -0.0027 -6.75] -""" -function JSON3_str_to_Array(json3_str::String) - d = JSON3.read(json3_str) - array = reshape(Array(d.Array), (d.size[1], d.size[2])) - return array -end - -#[WORKING] """ JSON_str_to_Array(json_str::String) decode JSON String to Array @@ -237,33 +304,95 @@ end """ function JSON_str_to_Array(jsonStr::String) jsonObj = JSON.parse(jsonStr) - array = reshape(Array(jsonObj.Array), (jsonObj.size[1], jsonObj.size[2])) + a = Array(jsonObj.Array) + array = hcat(a...) return array end - - # ---------------------------------------------- 100 --------------------------------------------- # -""" Convert JSON3.read object to OrderedDict +""" Recursively convert dictionary-like variable (e.g. JSON.Object) into a dictionary. - # Example - dict = dictionary(["a"=>4, "b"=>6]) - OrDict = OrderedDict(dict) - jsonString = JSON3.write(OrDict) # use jsonString to exchange. One can save it to file or send it thru pub/sub - jsonObject = JSON3.read(jsonString) - OrDict2 = JSON3read_to_OrDict(jsonObject) # example here - Adict2 = dictionary(OrDict2) +# What it does + - Walks any nested structure composed of AbstractDict (e.g., JSON.Object, + Dict, OrderedDict) and AbstractArray and produces a new tree where + every dictionary-like node is an OrderedDict{Any,Any} and every array-like + node is a Vector{Any}. Scalar values (numbers, strings, booleans, + nothing, etc.) are returned unchanged. + - Does **not** mutate the input; it always allocates new containers. - Andyferris's github https://github.com/andyferris/Dictionaries.jl +# Arguments +- `x` + Any Julia value. If x is an AbstractDict it will be converted to an + OrderedDict{Any,Any}. if it is an AbstractArray its elements will be + processed recursively. + +# Keyword Arguments +- `stringkey::Bool=false` + If `true`, every dictionary key is converted to `String` via `string(k)`. + If `false`, original key objects are preserved (useful when keys are already + `String`, `Symbol`, or other types you want to keep). + +# Return +- A newly allocated nested structure composed of `OrderedDict{Any,Any}` and + `Vector{Any}` that mirrors the input shape but uses ordered Julia containers. + +# Notes +- The function treats any `AbstractDict` as a mapping source, so it works with + `JSON.Object`, `Dict`, `OrderedDict`, etc. +- Arrays are returned as `Vector{Any}` with their elements processed recursively. + +# Examples +```jldoctest +julia> using JSON +julia> d = Dict( + "a" => 4, + "b" => 6, + "c" => Dict( + "d"=>7, + :e=>Dict( + "f"=>"hey", + "g"=>Dict( + "world"=>[1, "2", 3, Dict(:dd=>4.7)] + ) + ) + ) + ) + +julia jsonstring = JSON.json(d) +julia> A1 = JSON.parse(jsonstring) # A1 type is JSON.Object +julia> A2 = OrderedDict(A1) +Dict{Any,Any} with 3 entries: + "a" => 4 + "b" => 6 + "c" => Dict("d"=>7, "e"=>Dict("f"=>"hey", "g"=>Dict("world"=>[1, "2", 3, 4.7]))) + +julia> A3 = OrderedDict(A1; stringkey=false) # preserves original key objects +julia> B1 = OrderedDict(d; stringkey=true) # convert all keys in to string +Dict{Any, Any} with 3 entries: + "c" => Dict{Any, Any}("e"=>Dict{Any, Any}("f"=>"hey", "g"=>Dict{Any, Any}("world"=>Any[1, "2", 3, Dict{Any, Any}("dd"=>4.7)])), "d"=>7) + "b" => 6 + "a" => 4 +``` +Ref. https://github.com/andyferris/Dictionaries.jl """ -function JSON3read_to_OrDict(x) - dict = OrderedDict() - for (k, v) in x - k = string(k) - dict[k] = v +function ordereddictify(x; stringkey::Bool=false) + # Dict-like objects + if x isa AbstractDict + # choose output key type container (String keys when requested) + out = OrderedDict{Any,Any}() + for (k,v) in x + newk = stringkey ? string(k) : k + out[newk] = ordereddictify(v; stringkey=stringkey) + end + return out + # Arrays / vectors: map elements recursively and return a Vector{Any} + elseif x isa AbstractArray + return [ordereddictify(element; stringkey=stringkey) for element in x] + # everything else: return as-is (primitives, numbers, strings, etc.) + else + return x end - return dict end #------------------------------------------------------------------------------------------------100 @@ -1227,6 +1356,7 @@ Detects if a keyword exists in the text in different case variations (lowercase, julia> detectKeywordVariation("missing", "complete data") nothing + ``` """ function detectKeywordVariation(keyword::String, text::String)::Union{Nothing, Array{String}} # Define the keyword variations to search for