I have a user-defined structure:
using Parameters
#with_kw struct TypeSingle
id::Int
x::Union{Int32, Missing} = missing
flag::Bool = true
end
#with_kw struct TypeAll
A = TypeSingle(id=01,x=0.1,flag=false)
B = TypeSingle(id=02)
# this continues on until
Z = TypeSingle(id=26,x=1.3)
end
I have some questions regarding operations that I would like to perform with TypeAll:
I'd like to refer to each entry, A.id, B.id etc.. in the composite TypeAll in a loop that runs from the lowest id to the highest.
Is there a way to extract the size of this type? i.e. how many A,B,...Z are there in total?
Would this be better suited to a vector of TypeA? In my actual code TypeAll isn't only composed of TypeA, but also includes TypeB, TypeC etc..
As long as your TypeAll is not going to be mutable, it looks a lot like a named tuple (NamedTuple) so why not use one instead of a TypeAll? e.g.
julia> t = (A = (01, 0.1, false), B = (02, missing, true), C = (26, 1.3, true))
(A = (1, 0.1, false), B = (2, missing, true), C = (26, 1.3, true))
julia> t[1]
(1, 0.1, false)
julia> length(t)
3
julia> sort(collect(t), lt = (x, y) -> x[1] < y[1])
3-element Vector{Tuple{Int64, Any, Bool}}:
(1, 0.1, 0)
(2, missing, 1)
(26, 1.3, 1)
If you want to have TypeAll mutable, I would use a vector of TypeSingle, instead of a named tuple.
Related
How can I limit the digits of data matrix to 2 digits?
data = reshape([tuple(c[i], c2[i]) for i in eachindex(c, c2)], 9, 9)
#9×9 Matrix{Tuple{Real, Real}}:
hl = Highlighter((d,i,j)->d[i,j][1]*d[i,j][2] < 0, crayon"red")
pretty_table(data ; header = names, row_names= names , highlighters=hl)
There are a couple of ways to do this:
You can use the round function:
data = round(data, 2)
You can use string formatting:
data = ["{0:.2f}".format(x) for x in data]
You can round the numbers when creating the data variable:
round2(n) = round(n; digits = 2)
data = reshape([tuple(round2(c[i]), round2(c2[i])) for i in eachindex(c, c2)], 9, 9)
Or if you want to maintain precision in the data array, but limit to 2 digits just for the printing, you can use the formatters keyword argument of PrettyTables:
pretty_table(data; header = titles, row_names = titles, formatters = (v, i, j) -> round.(v; digits = 2))
You can use an anonymous function as a formatter, like this:
formatter = (v, i, j) -> round(v, digits=2);
hl = Highlighter((d,i,j)->di,j*d[i,j][2] < 0, crayon"red")
pretty_table(data; header=names, row_names=names , highlighters=hl, formatters=formatter)
I encourage you to read the documentations for further options.
I understand you have a matrix of tuples such as:
julia> mx = [tuple(rand(2)...) for i in 1:3, j=1:2]
3×2 Matrix{Tuple{Float64, Float64}}:
(0.617653, 0.0742714) (0.0824311, 0.0344668)
(0.327074, 0.235599) (0.912262, 0.0250492)
(0.116079, 0.387601) (0.804606, 0.81485)
This can be rounded as:
julia> (x->round.(x;digits=2)).(mx)
3×2 Matrix{Tuple{Float64, Float64}}:
(0.62, 0.07) (0.08, 0.03)
(0.33, 0.24) (0.91, 0.03)
(0.12, 0.39) (0.8, 0.81)
Is there a way in Julia to smoothly define a recursive function?
function f(x_0, y_0)
x_1 = g1(x_0,y_0)
y_1 = g2(x_0,y_0)
x_2 = g1(x_1,y_1)
y_2 = g2(x_1,y_1)
x_3 = g1(x_2,y_2)
y_3 = g2(x_2,y_2)
x_4 = g1(x_3,y_3)
y_4 = g2(x_3,y_3)
return x_2,y_2
end
In particular, I want to be able to call the function and give parameter that would specify the circle of the recursion. Something like this:
f(x_0, y_0, circle = 2)
>> x_2, y_2
f(x_0, y_0, circle = 3)
>> x_3, y_3
If you define
function apply_n(f, x_0, cycle_len)
for _ in 1:cycle_len
x_0 = f(x_0)
end
return x0
end
and call apply_n((x,y)->(g1(x,y),g2(x,y)), (x_0,y_0), 3) it will work.
IterTools.jl provides an iterate method that does exatly this.
help?> iterated
…
iterated(f, x)
Iterate over successive applications of f, as in x, f(x), f(f(x)), f(f(f(x))), ...
…
julia> x_0, y_0 = 5, 10;
g1 = +;
g2 = -;
julia> using IterTools: iterated, nth
julia> nth(iterated(((x, y),) -> (g1(x, y), g2(x, y)), (x_0, y_0)), 3)
(10, 20)
As the documentation says, the result is (an iterator over) (x, f(x), f(f(x)), …), which means (x_2, y_2) from the question would be f(f(x)) which is the third element - that's why the call to nth above passes 3 as the second argument.
An advantage of this method is that it returns an iterator that you can then treat like any other iterator. So if you instead want the results of all the first 5 stages of the process:
julia> using Base.Iterators: take
julia> take(iterated(((x, y),) -> (g1(x, y), g2(x, y)), (x_0, y_0)), 5) |> collect
10-element Vector{Tuple{Int64, Int64}}:
(5, 10)
(15, -5)
(10, 20)
(30, -10)
(20, 40)
Or only want the recursion to continue while a condition is true:
julia> using Iterators: takewhile
julia> takewhile(((x, y),) -> x + y < 50,
iterated(((x, y),) -> (g1(x, y), g2(x, y)), (x_0, y_0))) |> collect
4-element Vector{Tuple{Int64, Int64}}:
(5, 10)
(15, -5)
(10, 20)
(30, -10)
I am trying to write a mutating function where the value passed as first argument mutates depending on the second one.
As an example, remove_when_zero_in_b below should return the values in vector a for those indexes where vector b is not 0.
"""filters 'a' when there is a zero in 'b'"""
function remove_when_zero_in_b!(a::AbstractVector, b::Vector{<:Real})
a = a[b .!= 0]
a
end
E.g.
x = [1.0, 2.0, 3.0, 4.0, 5.0]
y = [0, 1, 0, 2 , 0 ]
remove_when_zero_in_b!(x, y) # should mutate x
Then x should be:
println(x)
2-element Vector{Float64}:
2.0
4.0
However, the function above does not mutate x and remains as the initial vector with 5 elements.
What am I missing here? How would a function mutating x so I obtain the desired result look like?
a = a[b .!= 0] create a new copy of a, you can write,
function remove_when_zero_in_b!(a::AbstractVector, b::Vector{<:Real})
deleteat!(a, b .== 0)
a
end
I have two vertices (a) and (b) and I want to recursively split them at their midpoints.
The pattern looks like this:
For this specific depth I can write it like this:
a_b = self.abfn( a, b)
ab_b = self.abfn( a_b, b)
a_ab = self.abfn( a, a_b)
abb_b = self.abfn(ab_b, b)
ab_abb = self.abfn( a_b, ab_b)
a_aab = self.abfn( a, a_ab)
aab_ab = self.abfn(a_ab, a_b)
However I want to write it such that I can define a depth and repeatedly split to that depth.
The one caveat is I do not want to use recursive functions
How can I iterate in this manner?
I'm using python but the language doesn't really matter.
You could use this code:
def midpoint(a, b):
return ((a[0] + b[0]) / 2, (a[1] + b[1]) / 2)
def abfn(a, b, depth):
vertices = [a, b]
for _ in range(depth):
nextlevel = vertices[:1]
for a, b in zip(vertices, vertices[1:]): # all consecutive pairs
mid = midpoint(a, b)
nextlevel.extend((mid, b))
vertices = nextlevel
return vertices
Example call:
a = (0, 100)
b = (0, 200)
vertices = abfn(a, b, 2)
print(vertices)
Output:
[(0, 100), (0.0, 125.0), (0.0, 150.0), (0.0, 175.0), (0, 200)]
Is there a generator/iterator function that will turn
a = [1,2]
b = [3,4]
into [(1,3),(2,4)] and
a = 1
b = [3,4]
into [(1,3),(1,4)] using the same expression?
Is there a similar way to create a named tuple such as [(a=1,b=3),(a=1,b=4)]?
You can use broadcasting with Julia's dot syntax for this:
julia> tuple.(a, b)
2-element Array{Tuple{Int64,Int64},1}:
(1, 3)
(2, 4)
tuple here is a function that just creates a tuple from its arguments.
For NamedTuples you can either call the lower-level constructor directly on tuples with
julia> NamedTuple{(:a, :b)}.(tuple.(a, b))
2-element Array{NamedTuple{(:a, :b),Tuple{Int64,Int64}},1}:
(a = 1, b = 3)
(a = 2, b = 4)
where :a and :b are the sorted key names, or equivalently, using an anonymous function:
julia> broadcast((a_i, b_i) -> (a=a_i, b=b_i), a, b)
2-element Array{NamedTuple{(:a, :b),Tuple{Int64,Int64}},1}:
(a = 1, b = 3)
(a = 2, b = 4)
Hope that helps!
Just broadcast the tuple function.
julia> a = [1,2]; b=[3,4];
julia> tuple.(a,b)
2-element Array{Tuple{Int64,Int64},1}:
(1, 3)
(2, 4)
julia> tuple.(1, b)
2-element Array{Tuple{Int64,Int64},1}:
(1, 3)
(1, 4)
Second question - broadcast the constructor:
julia> NamedTuple{(:a, :b)}.(tuple.(1, b))
2-element Array{NamedTuple{(:a, :b),Tuple{Int64,Int64}},1}:
(a = 1, b = 3)
(a = 1, b = 4)