update docs
This commit is contained in:
+1
-1
@@ -1,6 +1,6 @@
|
||||
name = "GeneralUtils"
|
||||
uuid = "c6c72f09-b708-4ac8-ac7c-2084d70108fe"
|
||||
version = "0.4.0"
|
||||
version = "0.4.1"
|
||||
authors = ["tonaerospace <tonaerospace.etc@gmail.com>"]
|
||||
|
||||
[deps]
|
||||
|
||||
+354
-96
@@ -5,7 +5,7 @@ export noNegative!, randomWithProb, randomChoiceWithProb, findIndex, limitvalue,
|
||||
replaceLessThan, replaceBetween, cartesianAssign!, sumAlongDim3, matMul3Dto3DmanyTo1batch,
|
||||
matMul_3Dto4D_batchwise, isNotEqual, linearToCartesian, vectorMax, findMax,
|
||||
multiply_last, multiplyRandomElements, replaceElements, replaceElements!, isBetween,
|
||||
isLess, allTrue, getStringBetweenCharacters, JSON3read_stringKey, mkDictPath!,
|
||||
isLess, allTrue, getStringBetweenCharacters, mkDictPath!,
|
||||
getDictPath, detectKeywordVariation, textToDict, dictify, ordereddictify
|
||||
|
||||
using JSON, DataStructures, Distributions, Random, Dates, UUIDs, DataFrames, CSV
|
||||
@@ -152,12 +152,32 @@ end
|
||||
|
||||
""" read_textfile_by_index(folder_path::String, read_file_number::Integer=1)
|
||||
|
||||
with multiple text file in a folder,
|
||||
this function read x_th text file in a folder (filename is sorted by OS)
|
||||
# What it does
|
||||
- Reads the x-th text file from a folder, where files are listed by the OS
|
||||
without explicit sorting. Returns the file number, filename, and content.
|
||||
|
||||
# Example
|
||||
utils.read_textfile_by_index(cleaned_data_path, 2)
|
||||
read 2nd txt file in a folder
|
||||
# Arguments
|
||||
- `folder_path::String`
|
||||
Path to the folder containing text files.
|
||||
- `read_file_number::Integer=1`
|
||||
Which file to read (1-based index). Defaults to the first file.
|
||||
|
||||
# Return
|
||||
- A tuple of `(file_number::Integer, filename::String, content)` where:
|
||||
- `file_number` is the index of the file that was read
|
||||
- `filename` is the actual filename string
|
||||
- `content` is a vector of lines from the file (or `nothing` if error)
|
||||
|
||||
# Notes
|
||||
- Errors if `folder_path` is not a valid directory.
|
||||
- Errors if `read_file_number` exceeds the number of files in the folder.
|
||||
|
||||
# Examples
|
||||
```jldoctest
|
||||
julia> using GeneralUtils
|
||||
julia> result = read_textfile_by_index("/path/to/folder", 2)
|
||||
(2, "sample.txt", ["line1", "line2", ...])
|
||||
```
|
||||
"""
|
||||
function read_textfile_by_index(folder_path::String, read_file_number::Integer=1)
|
||||
if isdir(folder_path)
|
||||
@@ -453,6 +473,34 @@ function randomChoiceOnTarget(target::AbstractVector, choiceList::AbstractVector
|
||||
return randomChoiceOnTarget.(target, 1, (choiceList,), (probability,))
|
||||
end
|
||||
|
||||
""" Compute the linearly weighted average of an array.
|
||||
|
||||
# What it does
|
||||
- Assigns weights proportional to position indices (1, 2, 3, ...) to array
|
||||
elements and returns the weighted average.
|
||||
|
||||
# Arguments
|
||||
- `a::Array`
|
||||
Array of numeric values. Elements must support multiplication with numbers
|
||||
and summation.
|
||||
|
||||
# Return
|
||||
- The linearly weighted average as a floating-point number.
|
||||
|
||||
# Formula
|
||||
For an array `a` with `n` elements, computes:
|
||||
```
|
||||
sum(i * a[i]) / sum(a) for i = 1 to n
|
||||
```
|
||||
|
||||
# Examples
|
||||
```jldoctest
|
||||
julia> using GeneralUtils
|
||||
julia> a = [10, 20, 30]
|
||||
julia> linearly_weighted_avg(a)
|
||||
23.333333333333332
|
||||
```
|
||||
"""
|
||||
function linearly_weighted_avg(a::Array)
|
||||
total = 0.0
|
||||
for (i, v) in enumerate(a)
|
||||
@@ -463,10 +511,36 @@ function linearly_weighted_avg(a::Array)
|
||||
end
|
||||
|
||||
|
||||
""" Convert String that is holded inside a variable to Symbol
|
||||
# Example
|
||||
x = "hello" # x is a variable holding String "hello" \n
|
||||
y = variable_to_symbol(x) # y holds :hello
|
||||
""" Convert a variable's value (String) into a Symbol.
|
||||
|
||||
# What it does
|
||||
- Takes a variable containing a String value and converts it to a Symbol
|
||||
using Julia's expression interpolation mechanism.
|
||||
|
||||
# Arguments
|
||||
- `variable`
|
||||
Any variable whose value is a String. The function uses `string(variable)`
|
||||
internally to obtain the value.
|
||||
|
||||
# Return
|
||||
- A `Symbol` constructed from the string value of the input variable.
|
||||
|
||||
# Notes
|
||||
- This function uses `:$variable` interpolation to capture the variable's
|
||||
value as a Symbol. It works with any variable type that can be converted
|
||||
to String.
|
||||
|
||||
# Examples
|
||||
```jldoctest
|
||||
julia> using GeneralUtils
|
||||
julia> x = "hello"
|
||||
julia> variable_str_to_symbol(x)
|
||||
:hello
|
||||
|
||||
julia> y = "world_test"
|
||||
julia> variable_str_to_symbol(y)
|
||||
:world_test
|
||||
```
|
||||
"""
|
||||
function variable_str_to_symbol(variable)
|
||||
semi = :($variable)
|
||||
@@ -510,6 +584,45 @@ function fieldname_useable_type(somestruct, fieldname::Symbol;
|
||||
end
|
||||
|
||||
|
||||
""" Draw unique elements from a list without replacement.
|
||||
|
||||
# What it does
|
||||
- Randomly selects a specified number of distinct elements from a collection,
|
||||
optionally excluding certain elements from consideration. Uses in-place
|
||||
shuffling for efficiency.
|
||||
|
||||
# Arguments
|
||||
- `drawOptions::Array`
|
||||
Collection of elements to draw from.
|
||||
- `draw_number::Integer`
|
||||
Number of unique elements to draw.
|
||||
|
||||
# Keyword Arguments
|
||||
- `exclude_list::Union{AbstractArray,Nothing}=nothing`
|
||||
Elements to exclude from the drawing pool. If `nothing`, no elements are
|
||||
excluded.
|
||||
|
||||
# Return
|
||||
- An array of `draw_number` unique elements drawn from `drawOptions`, excluding
|
||||
any elements in `exclude_list`.
|
||||
|
||||
# Notes
|
||||
- The function copies `drawOptions` and shuffles in-place, then pops elements
|
||||
sequentially to ensure uniqueness.
|
||||
- Errors if `draw_number` exceeds the number of available elements after
|
||||
exclusion.
|
||||
|
||||
# Examples
|
||||
```jldoctest
|
||||
julia> using GeneralUtils
|
||||
julia> options = [1, 2, 3, 4, 5]
|
||||
julia> randomNoRepeat(options, 3)
|
||||
[3, 1, 5]
|
||||
|
||||
julia> randomNoRepeat(options, 2; exclude_list=[1, 5])
|
||||
[4, 2]
|
||||
```
|
||||
"""
|
||||
function randomNoRepeat(drawOptions::Array, draw_number::Integer;
|
||||
exclude_list::Union{AbstractArray,Nothing}=nothing)
|
||||
draw_option = copy(drawOptions)
|
||||
@@ -676,22 +789,49 @@ function selectRange(d::Dict{Symbol, <:AbstractVector}, range)
|
||||
return newDict
|
||||
end
|
||||
|
||||
""" Assign value to a given Dict by array of keys
|
||||
""" assignDict!(dict::Dict, accessArray::Array{Symbol}, valueToAssign)
|
||||
|
||||
# Example
|
||||
d = Dict(
|
||||
:a1=> Dict(:c=> 5),
|
||||
:a2=> Dict(
|
||||
:k=> 10,
|
||||
:b=> Dict(
|
||||
:s=> "target",
|
||||
)
|
||||
)
|
||||
)
|
||||
index = [:a2, :b, :s] \n
|
||||
assignDict!(d, [:a2, :b, :s], "wow")
|
||||
# What it does
|
||||
- Recursively traverses a nested dictionary structure using a vector of keys
|
||||
and assigns a value to the final key. Creates intermediate dictionaries
|
||||
if they don't exist.
|
||||
|
||||
return 1 if no target key in a given dict.
|
||||
# Arguments
|
||||
- `dict::Dict`
|
||||
The root dictionary to traverse and modify.
|
||||
- `accessArray::Array{Symbol}`
|
||||
A vector of symbols representing the key path to traverse.
|
||||
- `valueToAssign`
|
||||
The value to assign at the final key in the path.
|
||||
|
||||
# Return
|
||||
- `0` on success (value assigned)
|
||||
- `1` if the path cannot be traversed (missing intermediate keys)
|
||||
|
||||
# Notes
|
||||
- The function walks through each key in `accessArray` except the last one,
|
||||
expecting intermediate keys to already exist in the dictionary.
|
||||
- If any intermediate key is missing, the function returns `1` without
|
||||
modifying the dictionary.
|
||||
- The final key in `accessArray` receives the `valueToAssign`.
|
||||
|
||||
# Examples
|
||||
```jldoctest
|
||||
julia> using GeneralUtils
|
||||
julia> d = Dict(
|
||||
:a1=> Dict(:c=> 5),
|
||||
:a2=> Dict(
|
||||
:k=> 10,
|
||||
:b=> Dict(
|
||||
:s=> "target",
|
||||
)
|
||||
)
|
||||
)
|
||||
julia> assignDict!(d, [:a2, :b, :s], "wow")
|
||||
0
|
||||
julia> d[:a2][:b][:s]
|
||||
"wow"
|
||||
```
|
||||
"""
|
||||
function assignDict!(dict::Dict, accessArray::Array{Symbol}, valueToAssign)
|
||||
wd = nothing
|
||||
@@ -712,9 +852,42 @@ function assignDict!(dict::Dict, accessArray::Array{Symbol}, valueToAssign)
|
||||
end
|
||||
end
|
||||
|
||||
""" convert hour(0-23), minute(0-59) into julia time object
|
||||
# Example
|
||||
time
|
||||
""" iTime(h::Integer, m::Integer)
|
||||
|
||||
# What it does
|
||||
- Converts hour (0-23) and minute (0-59) into a Julia `Time` object using
|
||||
12-hour format with AM/PM indicator.
|
||||
|
||||
# Arguments
|
||||
- `h::Integer`
|
||||
Hour in 24-hour format (0 to 23).
|
||||
- `m::Integer`
|
||||
Minute (0 to 59).
|
||||
|
||||
# Return
|
||||
- A `Time` object representing the time in 12-hour format with AM/PM.
|
||||
|
||||
# Notes
|
||||
- Hours 0 and 12 are special cases: 0 becomes 12 AM, 12 becomes 12 PM.
|
||||
- Hours 1-11 remain the same with "am" suffix.
|
||||
- Hours 13-23 are converted to 1-11 with "pm" suffix.
|
||||
- Minutes less than 10 are zero-padded.
|
||||
|
||||
# Examples
|
||||
```jldoctest
|
||||
julia> using GeneralUtils
|
||||
julia> iTime(0, 30)
|
||||
12:30 AM
|
||||
|
||||
julia> iTime(9, 15)
|
||||
9:15 AM
|
||||
|
||||
julia> iTime(12, 0)
|
||||
12:00 PM
|
||||
|
||||
julia> iTime(14, 5)
|
||||
2:05 PM
|
||||
```
|
||||
"""
|
||||
function iTime(h::Integer, m::Integer)
|
||||
if h == 0
|
||||
@@ -758,19 +931,40 @@ function limitvalue(v::Number, lowerbound::Pair, upperbound::Pair)
|
||||
end
|
||||
|
||||
|
||||
""" Assign matrix b to matrix a according to matrix b's CartesianIndex.
|
||||
""" cartesianAssign!(a, b)
|
||||
|
||||
Arguments:\n
|
||||
a : target matrix.
|
||||
b : source matrix.
|
||||
# What it does
|
||||
- Assigns elements from matrix `b` to matrix `a` using the Cartesian indices
|
||||
of `b`. Elements are copied in the order they appear when iterating over `b`,
|
||||
and placed into `a` at the corresponding Cartesian positions of `b`.
|
||||
|
||||
Return:\n
|
||||
Resulting matrix a.
|
||||
# Arguments
|
||||
- `a`
|
||||
Target matrix where values from `b` will be assigned.
|
||||
- `b`
|
||||
Source matrix whose Cartesian indices determine where values are placed in `a`.
|
||||
|
||||
Example:\n
|
||||
```jldoctest
|
||||
julia> not done yet
|
||||
```
|
||||
# Return
|
||||
- `nothing`
|
||||
|
||||
# Notes
|
||||
- The function iterates through `b` in column-major order (Julia's default),
|
||||
retrieving each element's Cartesian index and assigning it to the same
|
||||
position in `a`.
|
||||
- Matrix `a` must have sufficient size to accommodate all Cartesian indices
|
||||
from `b`; otherwise, an `BoundsError` may occur.
|
||||
|
||||
# Examples
|
||||
```jldoctest
|
||||
julia> using GeneralUtils
|
||||
julia> a = zeros(4, 4);
|
||||
julia> b = [1 2; 3 4];
|
||||
julia> cartesianAssign!(a, b);
|
||||
julia> a[1:2, 1:2]
|
||||
2×2 Matrix{Float64}:
|
||||
1.0 3.0
|
||||
2.0 4.0
|
||||
```
|
||||
"""
|
||||
function cartesianAssign!(a, b)
|
||||
for (i, v) in enumerate(b)
|
||||
@@ -1125,7 +1319,6 @@ julia> text = "{\"ask\": {\"text\": \"Could you please tell me about the special
|
||||
julia> GeneralUtils.getStringBetweenCharacters(text, '{', '}', endCharLocation="end")
|
||||
"{\"ask\": {\"text\": \"Could you please tell me about the special event?\"\n}}"
|
||||
```
|
||||
# Signature
|
||||
"""
|
||||
function getStringBetweenCharacters(text::T, startChar::Char, endChar::Char;
|
||||
endCharLocation::String="next", includeChar::Bool=true)::String where {T<:AbstractString}
|
||||
@@ -1157,59 +1350,43 @@ function getStringBetweenCharacters(text::T, startChar::Char, endChar::Char;
|
||||
end
|
||||
|
||||
|
||||
""" mkDictPath!(dict::Union{Dict{Symbol, Any}, Dict{String, Any}}, addkeys::Union{Vector{String}, Vector{Symbol}}, value)
|
||||
|
||||
""" Read JSON string and return a dictionary with string key. (JSON3 defaults to symbol key)
|
||||
This function solve the problem of reading JSON with string key.
|
||||
|
||||
Arguments:
|
||||
jsonString::String
|
||||
|
||||
Return:
|
||||
a dictionary with string key
|
||||
|
||||
Example:
|
||||
```jldoctest
|
||||
julia> jsonString = {\"wine type\": \"Red\", \"intensity level\": \"medium-bodied\"}
|
||||
julia> JSON3read_stringKey(jsonString)
|
||||
Dict{String, Any} with 2 entries:
|
||||
"intensity level" => "medium-bodied"
|
||||
"wine type" => "Red"
|
||||
```
|
||||
"""
|
||||
function JSON3read_stringKey(jsonString::AbstractString)
|
||||
jsonobj = JSON3.read(jsonString)
|
||||
newDict = OrderedDict{String,Any}()
|
||||
for (k,v) in jsonobj
|
||||
newDict[string(k)] = v
|
||||
end
|
||||
return newDict
|
||||
end
|
||||
|
||||
|
||||
""" Create nested dict path if it does not already exist. The same concept as Julia's mkpath()
|
||||
# What it does
|
||||
- Recursively creates nested dictionary paths if they do not exist and assigns
|
||||
a value to the final key. Similar to `mkpath()` but for dictionaries.
|
||||
|
||||
# Arguments
|
||||
- `dict::Dict`
|
||||
target dict
|
||||
- `addkeys::Union{Vector{String}, Vector{Symbol}}`
|
||||
keys to be added to dict
|
||||
- `value`
|
||||
value to be added to dict at final key in keypath
|
||||
- `dict::Union{Dict{Symbol, Any}, Dict{String, Any}}`
|
||||
The target dictionary to traverse and modify. Must use consistent key types
|
||||
(either all `String` or all `Symbol`).
|
||||
- `addkeys::Union{Vector{String}, Vector{Symbol}}`
|
||||
A vector of keys representing the path to traverse. Intermediate dictionaries
|
||||
are created if they don't exist.
|
||||
- `value`
|
||||
The value to assign at the final key in the path.
|
||||
|
||||
# Return
|
||||
- dict with added keypath
|
||||
- The assigned `value`.
|
||||
|
||||
# Example
|
||||
# Notes
|
||||
- The function ensures key type consistency: the type of keys being added must
|
||||
match the type of existing keys in the dictionary.
|
||||
- Intermediate dictionaries are automatically created with the appropriate key
|
||||
type when they don't exist.
|
||||
- The function walks through each key in `addkeys` except the last one,
|
||||
creating intermediate dictionaries as needed, and assigns `value` to the final
|
||||
key.
|
||||
|
||||
# Examples
|
||||
```jldoctest
|
||||
julia> using Revise
|
||||
julia> using GeneralUtils
|
||||
julia> d = Dict{String, Any}("a" => Dict{String, Any}("b" => 10))
|
||||
julia> GeneralUtils.mkDictPath!(d, ["a", "v", "x", "y", "z"], 42)
|
||||
Dict{String, Any} with 1 entry:
|
||||
"path" => Dict{Any, Any}("to"=>Dict{Any, Any}("nested"=>Dict{Any, Any}("value"=>42)))
|
||||
julia> d = Dict("a" => Dict("b" => 10))
|
||||
julia> mkDictPath!(d, ["a", "v", "x", "y", "z"], 42)
|
||||
42
|
||||
julia> d["a"]["v"]["x"]["y"]["z"]
|
||||
42
|
||||
```
|
||||
|
||||
# Signature
|
||||
"""
|
||||
function mkDictPath!(dict::Union{Dict{Symbol, Any}, Dict{String, Any}},
|
||||
addkeys::Union{Vector{String}, Vector{Symbol}}, value)
|
||||
@@ -1233,27 +1410,36 @@ function mkDictPath!(dict::Union{Dict{Symbol, Any}, Dict{String, Any}},
|
||||
end
|
||||
|
||||
|
||||
""" Get nested dict value using a vector of keys
|
||||
""" getDictPath(dict::Dict, keys::Vector)
|
||||
|
||||
# What it does
|
||||
- Retrieves a value from a nested dictionary by traversing a vector of keys.
|
||||
Creates intermediate dictionaries if they don't exist.
|
||||
|
||||
# Arguments
|
||||
- `dict::Dict`
|
||||
target dict
|
||||
- `keys::Vector`
|
||||
keys vector
|
||||
- `dict::Dict`
|
||||
The root dictionary to traverse.
|
||||
- `keys::Vector`
|
||||
A vector of keys representing the path to traverse. Each key in the vector
|
||||
is used to access the next level of nesting.
|
||||
|
||||
# Return
|
||||
- dict with added keypath
|
||||
- The value at the final key in the path.
|
||||
|
||||
# Example
|
||||
# Notes
|
||||
- Errors with `ArgumentError` if any intermediate key is missing from the
|
||||
dictionary path.
|
||||
- The function walks through each key in `keys` except the last one,
|
||||
expecting intermediate keys to exist in the dictionary.
|
||||
- The final key in `keys` is used to retrieve the value.
|
||||
|
||||
# Examples
|
||||
```jldoctest
|
||||
julia> using Revise
|
||||
julia> using GeneralUtils
|
||||
julia> d = Dict{Symbol, Any}(:a => Dict{Symbol, Any}(:b => 10))
|
||||
julia> GeneralUtils.getDictPath(d, [:a, :b])
|
||||
julia> d = Dict(:a => Dict(:b => 10))
|
||||
julia> getDictPath(d, [:a, :b])
|
||||
10
|
||||
```
|
||||
|
||||
# Signature
|
||||
"""
|
||||
function getDictPath(dict::Dict, keys::Vector)
|
||||
current_dict = dict
|
||||
@@ -1405,8 +1591,6 @@ OrderedCollections.OrderedDict{Any, Any}(:thought => "what to do",
|
||||
:plan => "wake up and going out",
|
||||
:action => "1. wake up 2. eat 3. sleep")
|
||||
```
|
||||
|
||||
# Signature
|
||||
"""
|
||||
function textToDict(text::String, detectKeywords::Vector{String};
|
||||
dictKey::Union{Vector{String}, Nothing}=nothing,
|
||||
@@ -1467,6 +1651,80 @@ function textToDict(text::String, detectKeywords::Vector{String};
|
||||
return od2
|
||||
end
|
||||
|
||||
""" Recursively convert dictionary into an HTML string representation.
|
||||
|
||||
# What it does
|
||||
- Walks a nested `AbstractDict` structure and produces a well-formed HTML string
|
||||
where each dictionary key becomes an HTML tag. Nested dictionaries become
|
||||
nested tags, and scalar values (numbers, strings, etc.) become the text
|
||||
content of leaf tags.
|
||||
|
||||
# Arguments
|
||||
- `d::AbstractDict`
|
||||
The dictionary to convert. Keys must be strings or symbols that form valid
|
||||
HTML tag names.
|
||||
|
||||
# Keyword Arguments
|
||||
- `indent_level::Integer=1`
|
||||
Initial indentation level for the output. Each recursive level increases
|
||||
indentation by one.
|
||||
- `indent_str::String=" "`
|
||||
String used for each indentation level.
|
||||
|
||||
# Return
|
||||
- A single HTML string representing the dictionary structure, with proper
|
||||
opening and closing tags and appropriate indentation.
|
||||
|
||||
# Notes
|
||||
- Keys are sorted alphabetically for deterministic output.
|
||||
- Works recursively: dictionary values produce nested tags; non-dictionary
|
||||
values are placed as text between opening/closing tags.
|
||||
|
||||
# Examples
|
||||
```jldoctest
|
||||
julia> d = Dict(
|
||||
"html" => Dict(
|
||||
"head" => Dict("title" => "Test"),
|
||||
"body" => Dict(
|
||||
"h1" => "Hello",
|
||||
"p" => "World"
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
julia> println(dict_to_string_html(d))
|
||||
<html>
|
||||
<head>
|
||||
<title>Test</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Hello</h1>
|
||||
<p>World</p>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
"""
|
||||
function dict_to_string_html(d::AbstractDict; indent_level=1, indent_str=" ")
|
||||
lines = String[]
|
||||
padding = indent_str ^ indent_level
|
||||
|
||||
# Sort keys for predictable, clean output
|
||||
for k in sort(collect(keys(d)))
|
||||
v = d[k]
|
||||
|
||||
if v isa AbstractDict
|
||||
# Open tag, recurse for children, then close tag
|
||||
push!(lines, "$padding<$k>")
|
||||
ind_level = indent_level + 1
|
||||
push!(lines, dict_to_string_html(v; indent_level=ind_level, indent_str=indent_str))
|
||||
push!(lines, "$padding</$k>")
|
||||
else
|
||||
# Leaf node: put key and value on a single line
|
||||
push!(lines, "$padding<$k>$v</$k>")
|
||||
end
|
||||
end
|
||||
return join(lines, "\n")
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user