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

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.

Related

Outputting variable name and value in a loop

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

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...]

Filtering using conditional evaluation (&&)

I am having trouble filtering a simple array-based on two conditions. For example, to filter out values between 3 and 5, I tried the following but I get an ERROR: TypeError: non-boolean (BitArray{1}) used in boolean context error.
arr = Array{Int64}([1,2,3,4,5,6])
arr[(arr .> 3) && (arr.< 5)]
Any idea how to solve it?
Also on a side note, I am wondering if there is a function opposite to isless. Something to find a value greater than a certain value.
Here are two ways to do it:
julia> arr = [1,2,3,4,5,6]
6-element Array{Int64,1}:
1
2
3
4
5
6
julia> arr[(arr .> 3) .& (arr.< 5)]
1-element Array{Int64,1}:
4
julia> filter(v -> 3 < v < 5, arr)
1-element Array{Int64,1}:
4
(I personally prefer filter).
To get the opposite of isless just reverse its arguments, or if needed define a new function:
isgreater(x, y) = isless(y, x)
I prefer a set comparison approach because it's quite intuitive:
julia> arr = Array{Int64}([1,2,3,4,5,6])
julia> intersect( arr[ arr .> 1 ], arr[ arr .< 4 ] )
2-element Array{Int64,1}:
2
3
Or list comprehension:
[ x for x in arr if 3 < x < 5]
# or
[ x for x in arr if 3 < x && x < 5]
Also to define an array literal with specific type Int64, there is a dedicated syntax to make it simpler:
arr = Int64[1,2,3,4,5,6]

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()

How to pass keywords and keyword variable values to a function via Tuples

You can easily pass "normal" (i.e. non-keyword) variable values to a function via a Tuple with an ellipsis, like e.g.:
julia> f(x, y, z) = x + y + z;
julia> f(0, 1, 2)
3
julia> varvalues = 0, 1, 2
(0,1,2)
julia> f(varvalues...)
3
But for keyword variables, how do you pass both the keywords and the corresponding variable values via variables? Like e.g. (forgive the silly example):
julia> function g(x, y, z; operation = "add", format = "number")
operation == "add" && format == "number" && return x + y + z
operation == "add" && format == "string" && return string(x + y + z)
operation == "times" && format == "number" && return x * y * z
operation == "times" && format == "string" && return string(x * y * z)
end; # yep, I know this not type-stable
julia> g(0, 1, 2, operation = "times", format = "string")
"0"
julia> g(varvalues..., operation = "times", format = "string") # varvalues = (0,1,2)
"0"
So I would like to define two variables, analogous to varvalues above: keywords with the keywords and keywordvarvalues with the corresponding variable values, that can be passed to function g. Something like this, but that works:
julia> keywords = :operation, :format
(:operation,:format)
julia> keywordvarvalues = "times", "string"
("times","string")
julia> g(varvalues..., keywords... = keywordvarvalues...)
ERROR: MethodError: no method matching broadcast!...
I suppose I can always compose this String from keywords and keywordvarvalues:
expressionstring = """g(varvalues..., operation = "times", format = "string")"""
and then parse-eval it, but that's prolly bad practice, no?
This works:
julia> keywords = :operation, :format
(:operation,:format)
julia> keywordvarvalues = 10, 20
(10,20)
julia> g(; operation=1, format=2) = (operation, format)
g (generic function with 1 method)
julia> g(; zip(keywords, keywordvarvalues)...)
(10,20)
You can also use dictionaries:
julia> g(; keywords...) = keywords
julia> g(a=3, b=4)
2-element Array{Any,1}:
(:a,3)
(:b,4)
julia> d = Dict(:c=>5, :d=>6)
Dict{Symbol,Int64} with 2 entries:
:c => 5
:d => 6
julia> g(; d...)
2-element Array{Any,1}:
(:c,5)
(:d,6)

Resources