Outputting variable name and value in a loop - julia

I want to loop over a list of variables nad output the variable name and value. E.g., say I have x=1 and y=2, then I want an output
x is 1
y is 2
I suspect I need to use Symbols for this. Here is my approach, but it isn't working:
function t(x,y)
for i in [x,y]
println("$(Symbol(i)) is $(eval(i))") # outputs "1 is 1" and "2 is 2"
end
end
t(1, 2)
Is there a way to achieve this? I guess a Dictionary would work, but would be interested to see if Symbols can also be used here.

One option is to use a NamedTuple:
julia> x = 1; y = 2
2
julia> vals = (; x, y)
(x = 1, y = 2)
julia> for (n, v) ∈ pairs(vals)
println("$n is $v")
end
x is 1
y is 2
Note the semicolon in (; x, y), which turns the x and y into kwargs so that the whole expression becomes shorthand for (x = x, y = y).
I will also add that your question looks like like you are trying to dynamically work with variable names in global scope, which is generally discouraged and an indication that you probably should be considering a datastructure that holds values alongside labels, such as the dictionary proposed in the other answer or a NamedTuple. You can google around if you want to read more on this, here's a related SO question:
Is it a good idea to dynamically create variables?

You can do this by passing the variable names:
x = 1
y = 2
function t(a, b)
for i in [a, b]
println("$(i) is $(eval(i))")
end
end
t(:x, :y)
x is 1
y is 2
At the start of the function, there's no record of the "x"-ness of x, or the "y"-ness of y. The function only sees 1 and 2. It's a bit confusing that you also called your two local variables x and y, I renamed them to show what's happening more clearly.
A solution with dictionaries would be nicer:
dict = Dict()
dict[:x] = 1
dict[:y] = 2
function t(d)
for k in keys(d)
println("$(k) is $(d[k])")
end
end
t(dict)
y is 2
x is 1

If you rather want to see programmatically what variables are present you could use varinfo or names:
julia> x=5; y=7;
julia> varinfo()
name size summary
–––––––––––––––– ––––––––––– –––––––
Base Module
Core Module
InteractiveUtils 316.128 KiB Module
Main Module
ans 8 bytes Int64
x 8 bytes Int64
y 8 bytes Int64
julia> names(Main)
7-element Vector{Symbol}:
:Base
:Core
:InteractiveUtils
:Main
:ans
:x
With any given name it's value can be obtained via getfield:
julia> getfield(Main, :x)
5
If you are rather inside a function than use #locals macro:
julia> function f(a)
b=5
c=8
#show Base.#locals
end;
julia> f(1)
#= REPL[13]:4 =# Base.#locals() = Dict{Symbol, Any}(:a => 1, :b => 5, :c => 8)
Dict{Symbol, Any} with 3 entries:
:a => 1
:b => 5
:c => 8

Related

Julia - Equivalent of python `pop`. Remove elements from array using boolean array and return them

Is there an equivalent to Python's pop? I have an array x and a boolean array flag of the same length. I would like to extract x[flag] and be able to store it in a variable x_flagged while at the same time remove them in place from x.
x = rand(1:5, 100)
flag = x .> 2
x_flagged = some_function!(x, flag) # Now x would be equal to x[x .<= 2]
Try this one using deleteat!
julia> function pop_r!(list, y) t = list[y]; deleteat!( list, y ); t end
julia> x = rand(1:5, 100)
100-element Vector{Int64}
julia> flag = x .> 2
100-element BitVector
julia> pop_r!( x, flag )
60-element Vector{Int64}
julia> x
40-element Vector{Int64}
You can use splice! with a bit of help from findall:
julia> x_flagged = splice!(x, findall(flag))
59-element Vector{Int64}:
...
julia> size(x)
(41,)
splice!(a::Vector, indices, [replacement]) -> items
Remove items at specified indices, and return a collection containing the removed items.

How can I slice the high-order multidimeonal array (or tensor) on the specific axis in Julia?

I am using Julia1.6
Here, X is a D-order multidimeonal array.
How can I slice from i to j on the d-th axis of X ?
Here is an exapmle in case of D=6 and d=4.
X = rand(3,5,6,6,5,6)
Y = X[:,:,:,i:j,:,:]
i and j are given values which are smaller than 6 in the above example.
You can use the built-in function selectdim
help?> selectdim
search: selectdim
selectdim(A, d::Integer, i)
Return a view of all the data of A where the index for dimension d equals i.
Equivalent to view(A,:,:,...,i,:,:,...) where i is in position d.
Examples
≡≡≡≡≡≡≡≡≡≡
julia> A = [1 2 3 4; 5 6 7 8]
2×4 Matrix{Int64}:
1 2 3 4
5 6 7 8
julia> selectdim(A, 2, 3)
2-element view(::Matrix{Int64}, :, 3) with eltype Int64:
3
7
Which would be used something like:
julia> a = rand(10,10,10,10);
julia> selectedaxis = 5
5
julia> indices = 1:2
1:2
julia> selectdim(a,selectedaxis,indices)
Notice that in the documentation example, i is an integer, but you can use ranges of the form i:j as well.
If you need to just slice on a single axis, use the built in selectdim(A, dim, index), e.g., selectdim(X, 4, i:j).
If you need to slice more than one axis at a time, you can build the array that indexes the array by first creating an array of all Colons and then filling in the specified dimensions with the specified indices.
function selectdims(A, dims, indices)
indexer = repeat(Any[:], ndims(A))
for (dim, index) in zip(dims, indices)
indexer[dim] = index
end
return A[indexer...]
end
idx = ntuple( l -> l==d ? (i:j) : (:), D)
Y = X[idx...]

How to create a function of n variables (Julia)

For a fixed n, I would like to create a function with n variables
f(x_1, ..., x_n)
For example if n=3, I would like to create an algorithm such that
f(x_1, x_2, x_3) = x_1 + x_2 + x_3
It would be very nice to have an algorithm for every n:
f(x_1, ..., x_n) = x_1 + ... + x_n
I don't know how to declare the function and how can create the n variables.
Thank you for your help,
In Julia you can just do
function f(x...)
sum(x)
end
And now:
julia> f(1,2,3)
6
Note that within the function f, x is just seen as a Tuple so you can do whatever you want (including asking for type of elements etc).
More generally you can define function f(x...;y...). Let us give it a spin
function f(x...;y...)
#show x
#show Dict(y)
end
And now run it:
julia> f(1,2,"hello";a=22, b=777)
x = (1, 2, "hello")
Dict(y) = Dict(:a => 22, :b => 777)
Dict{Symbol, Int64} with 2 entries:
:a => 22
:b => 777
Finally, another one (perhaps less elegant) way could be:
g(v::NTuple{3,Int}) = sum(v)
This forces v to be a 3-element Tuple and g be called as g((1,2,3))
If your n is small, you can do this manually thanks to multiple dispatch.
julia> f(x) = x + 1 # Method definition for one variable.
f (generic function with 1 method)
julia> f(x, y) = x + y + 1 # Method definition for two variables.
f (generic function with 2 methods)
julia> f(2)
3
julia> f(2, 4)
7
You could use macro programming to generate a set of these methods automatically, but that quickly becomes complicated. You are likely better off structuring your function so that it operates on either a Vector or a Tuple of arbitrary length. The definition of the function will depend on what you want to do. Some examples which expect x to be a Tuple, Vector, or other similar datatype are below.
julia> g(x) = sum(x) # Add all the elements
g (generic function with 1 method)
julia> h(x) = x[end - 1] # Return the second to last element
h (generic function with 1 method)
julia> g([10, 11, 12])
33
julia> h([10, 11, 12])
11
If you would rather the function accept an arbitrary number of inputs rather than a single Tuple or Vector as you wrote in the original question, then you should define a method for the functions with the slurping operator ... as below. Note that the bodies of the function definitions and the outputs from the functions are exactly the same as before. Thus, the slurping operator ... is just for syntactical convenience. The functions below still operate on the Tuple x. The function arguments are just slurped into the tuple before doing anything else. Also note that you can define both the above and below methods simultaneously so that the user can choose either input method.
julia> g(x...) = sum(x) # Add all the variables
g (generic function with 2 methods)
julia> h(x...) = x[end - 1] # Return the second to last variable
h (generic function with 2 methods)
julia> g(10, 11, 12)
33
julia> h(10, 11, 12)
11
Finally, another trick that is sometimes useful is to call a function recursively. In other words, to have a function call itself (potentially using a different method).
julia> q(x) = 2 * x # Double the input
q (generic function with 1 method)
julia> q(x...) = q(sum(x)) # Add all the inputs and call the function again on the result
q (generic function with 2 methods)
julia> q(3)
6
julia> q(3, 4, 5)
24

How to broadcast set operation on array of sets in Julia?

I'm trying to perform set operations between a given set y and all items in some array of sets X as follows:
X=Array{Set}([Set([1,2,1]), Set([4,6,8 ]), Set([4,5])])
y=Set{Int16}([2,8,4])
z=broadcast(intersect, y, X)
println(z)
Which gives me empty sets, instead of sets with the singletons in y, for my example.
You have to protect y from being iterated over. Normally you would get an error but unfortunately y has three elements as well as vector X. Let us create a bigger vector then so see the problem:
julia> X=Array{Set}([Set([1,2,1]), Set([4,6,8 ]), Set([4,5]), Set([7])])
4-element Array{Set,1}:
Set([2, 1])
Set([4, 8, 6])
Set([4, 5])
Set([7])
julia> y=Set{Int16}([2,8,4])
Set{Int16} with 3 elements:
4
2
8
julia> z=broadcast(intersect, y, X)
ERROR: DimensionMismatch("arrays could not be broadcast to a common size; got a dimension with lengths 3 and 4")
How to solve it - wrap y in a 0-dimensional container with Ref(y) like this:
julia> z=broadcast(intersect, Ref(y), X)
4-element Array{Set{Int16},1}:
Set([2])
Set([4, 8])
Set([4])
Set()
or equivalently just write:
julia> z=intersect.(Ref(y), X)
4-element Array{Set{Int16},1}:
Set([2])
Set([4, 8])
Set([4])
Set()

Outer constructor that has the same number of arguments as the field values

How can I define an outer constructor that has same number of arguments as the field values? What I want to do is something like this:
struct data
x
y
end
function data(x, y)
return data(x-y, x*y)
end
But it obviously causes stackoverflow.
Based on the various helpful comments, thanks to all, I changed my answer. Here is an example in Julia 1.0.0 of what you may be after. I am learning Julia myself, so maybe further comments can improve this example code.
# File test_code2.jl
struct Data
x
y
Data(x, y) = new(x - y, x * y)
end
test_data = Data(105, 5)
println("Constructor example: test_data = Data(105, 5)")
println("test_data now is...: ", test_data)
#= Output
julia> include("test_code2.jl")
Constructor example: test_data = Data(105, 5)
test_data now is...: Data(100, 525)
=#
This works for me
julia> struct datatype
x
y
end
julia> function datatype_create(a,b)
datatype(a - b, a * b)
end
datatype_create (generic function with 1 method)
julia> methods(datatype_create)
# 1 method for generic function "datatype_create":
[1] datatype_create(a, b) in Main at none:2
julia> methods(datatype)
# 1 method for generic function "(::Type)":
[1] datatype(x, y) in Main at none:2
julia> a = datatype_create(105,5)
datatype(100, 525)
julia> b = datatype_create(1+2im,3-4im)
datatype(-2 + 6im, 11 + 2im)
julia> c = datatype_create([1 2;3 4],[4 5;6 7])
datatype([-3 -3; -3 -3], [16 19; 36 43])
julia> d = datatype_create(1.5,0.2)
datatype(1.3, 0.30000000000000004)
If you are absolutely Ideologically Hell Bent on using an outer constructor, then you can do something like this
julia> datatype(a,b,dummy) = datatype(a - b,a * b)
datatype
julia> e = datatype(105,5,"dummy")
datatype(100, 525)
Antman's solution using the power of MACRO
julia> macro datatype(a,b)
return :( datatype($a - $b , $a * $b) )
end
#datatype (macro with 1 method)
julia> f = #datatype( 105 , 5 )
datatype(100, 525)

Resources