How to create and modify named vector in Julia?

Hello,
I am setting a polynomial function and a vector (array) that passes the parameters to this function, something like this:

y = v[1]*x + v[2]*x^2 + v[3]*x^3

It would be easier to remember the elements of the vector if the elements were named as in:

 y = alpha*x + beta*x^2 + gamma*x^3

When setting the vector, I should remember the sequence of the elements and the same applies when changing an element, as in:

julia> v = [7,2,3]
3-element Vector{Int64}:
 7
 2
 3

julia> v[2] = 5
5

julia> v
3-element Vector{Int64}:
 7
 5
 3

Is it possible to name each element of the vector so that I don’t need to remember the sequence of elements and that I can change the elements by name only? Something like this:

v = [beta=7, alpha=0.5, gamma=3]
v:alpha=5

I see from this post that one can use the package NamedArrays that set a vector as an array of values and names:

julia> v = NamedArray([5, 7, 3], (["alpha", "beta", "gamma"]))
3-element Named Vector{Int64}
A     │ 
──────┼──
alpha │ 5
beta  │ 7
gamma │ 3

But then how are the elements changed?
Another way might be with the package Parsers:

v = (alpha=5, beta=7, gamma=3)

but this is a tuple that does not allow me to modify the elements.
Is there a simple way, preferably Julia base, to do name a vector and modify its elements by name?

Thank you

Hello,
Sounds to me like what you’re looking for is a Dict (an associative array).

v = Dict(:alpha => 5, :beta => 7, :gamma => 3)
Dict{Symbol, Int64} with 3 entries:
  :alpha => 5
  :beta  => 7
  :gamma => 3

julia> v[:alpha]
5

julia> v[:alpha] = 10
10

julia> v
Dict{Symbol, Int64} with 3 entries:
  :alpha => 10
  :beta  => 7
  :gamma => 3

See Collections and Data Structures · The Julia Language

It is a basic collection, so you don’t require any additional package.

BR Stefan

2 Likes

I like to use namedtuples with Accessors.jl

using Acccessors
julia> t1 = (;a=1, b=2)
(a = 1, b = 2)

julia> t2 = @set t1.a = 10
(a = 10, b = 2)

julia> t1
(a = 1, b = 2)
3 Likes

See

julia> A = @LArray [1.1, 2.2, 3.3] (:alpha, :beta, :gamma)
3-element LArray{Float64, 1, Vector{Float64}, (:alpha, :beta, :gamma)}:
 :alpha => 1.1
  :beta => 2.2
 :gamma => 3.3

julia> A[1:2]
2-element Vector{Float64}:
 1.1
 2.2

julia> A.alpha
1.1

julia> A.beta
2.2

julia> A.gamma
3.3

julia> A.gamma = π
π = 3.1415926535897...

julia> A[3]
3.141592653589793
6 Likes

Is there a characteristic length to these arrays? If they are fixed for a particular problem, and reasonably short, then named tuples should be very much suited.

I suspect they are, since using individual names for fields doesn’t seem meaningful for dynamically sized collections, or large.

Tuples are lightweight and much more efficient than arrays, so NamedTuples seems like a good fit. Modifying them can be done efficiently by replacing the entire tuple, as @jar1 suggests.

4 Likes

With NamedTuples and the merge function, you should be able to do all this while staying in the base

julia> v = (alpha=5, beta=7, gamma=3)
(alpha = 5, beta = 7, gamma = 3)

julia> v=merge(v,(beta=77,))
(alpha = 5, beta = 77, gamma = 3)

julia> v
(alpha = 5, beta = 77, gamma = 3)
7 Likes

StaticArrays with their FieldVector are a great fit for such a problem: they are vectors and support vector operations, and are as performant as tuples and namedtuples.
Of course, they are also supported by Accessors.jl for convenient value modifications.

4 Likes

If the vector has always the same number of components, you could also just create a mutable struct with those fields:

@kwdef mutable struct MyStruct
    beta::Float64
    alpha::Float64
    gamma::Float64
end

...

v = MyStruct(alpha=5, beta=7, gamma=3)
y = v.alpha * x + v.beta * x^2 + v.gamma * x^3

# Since MyStruct is mutable, you can easily change like:

v.alpha = pi
v.beta = -1
v.gamma = 0
2 Likes

Thank you but the problem with tuples is that I can’t modify them…
I’ll try these solutions.

Actually, there are two posts showing how you can ‘modify’ tuples, by creating a new one, using merge or Accessors.jl. For short tuples, this should be extremely efficient.

2 Likes

If you use namedtuples (or just tuples), you can also use evalpoly, which can have significant advantages over the naive way of evaluating a polynomial:

v = (beta=7, alpha=0.5, gamma=3)
evalpoly(3, Tuple(v))