Compare array values with a value in Julia - julia

I have an array a = [1, 2, 3, 4];. I want to compare each element of array a with a number and return a new array contains True/False elements in Julia as few steps as possible. I try result = a < 2 and expected array is result = [True, False, False, False] but it's not working. Hope your help

You need to vectorize (broadcast) the comparison operator so it operates on Vectors.
You can do this by adding a dot . to your code.
julia> a = [1, 2, 3, 4]
4-element Vector{Int64}:
1
2
3
4
julia> a .<= 2
4-element BitVector:
1
1
0
0
Read more about broadcasting here.
Note that Python's numpy will do this for you automatically, but there are cases where an operation might be ambiguous - do you want it to be element wise or a matrix multiplication? So Julia solves this by explicitly broadcasting any operation with the . command.

Related

Output variables containing numbers in a loop

I have the following variables
a1 = 2
a2 = 20
a3 = 200
Is it possible to output them while looping over the integers 1, 2 and 3? Something like the following although it doesn't work as intended
for i in [1,2,3]
println(:"a$i") # doesn't work
println("a" * string(i)) # doesn't work
end
You can use a dictionary, but this looks like a job for arrays:
julia> a = [2, 20, 200]
3-element Vector{Int64}:
2
20
200
julia> for i in eachindex(a)
println(a[i])
end
2
20
200
It is typical for beginner programmers to try to create and access variables dynamically. It is possible to do, but you should not do it. It makes code fragile and hard to read, and also slow and bug-prone. This is why data structures exist, that allow you to collect data in a structured way.
And alternative to arrays, is to use a tuple, a = (2, 20, 200). It works much the same way, except you cannot change a tuple after it has been created.
You could use a dictionary to store the variables:
julia> d = Dict("a1"=>2, "a2"=>20, "a3"=>200)
Dict{String, Int64} with 3 entries:
"a3" => 200
"a2" => 20
"a1" => 2
julia> for i in [1, 2, 3]
println(d["a$i"])
end
2
20
200

How to delete an element from a list in Julia?

v = range(1e10, -1e10, step=-1e8) # velocities [cm/s]
deleteat!(v, findall(x->x==0,v))
I want to delete the value 0 from v. Following this tutorial, I tried deleteat! but I get the error
MethodError: no method matching deleteat!(::StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}, Int64}, ::Vector{Int64})
What am I missing here?
Notice the type that is returned by the function range.
typeof(range(1e10, -1e10, step=-1e8))
The above yields to
StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}, Int64}
Calling the help function for the function deleteat!.
? deleteat!()
deleteat!(a::Vector, inds)
Remove the items at the indices given by inds, and return the > modified a. Subsequent items are shifted to fill the resulting gap.
inds can be either an iterator or a collection of sorted and > unique integer indices, or a boolean vector of the same length as a with true indicating entries to delete.
We can convert the returned type of range using collect. Try the following code.
v = collect(range(1e10, -1e10, step=-1e8))
deleteat!(v,findall(x->x==0,v))
Notice that we can shorten x->x==0 to iszero which yields to
v = collect(range(1e10, -1e10, step=-1e8))
deleteat!(v,findall(iszero,v))
Use filter! or filter:
julia> filter!(!=(0), [1,0,2,0,4])
3-element Vector{Int64}:
1
2
4
In case of a range you can collect it or use:
julia> filter(!=(0), range(2, -2, step=-1))
4-element Vector{Int64}:
2
1
-1
-2
However for big ranges you might just not want to materialize them to save the memory footprint. In that case you could use:
(x for x in range(2, -2, step=-1) if x !== 0)
To see what is being generated you need to collect it:
julia> collect(x for x in range(2, -2, step=-1) if x !== 0)
4-element Vector{Int64}:
2
1
-1
-2

How to add missing and value in Julia and get the value instead of missing

Is it possible with the new version of Julia (1.3.0) to add "missing" + 1 and get a "1" instead of a "missing"?? I want to sum two columns from an Array and skip the missings, but keeping the same number of rows. Thanks!
This is a somewhat unusual treatment of missing - if I understand you correctly you want missing to behave like a zero if added to another number, and like missing when added to another missing. Given that this is a bit unusual, I would just write it out explicitly:
julia> a = [1, missing, missing]; b = [2, 1, missing];
julia> ifelse.(ismissing.(a) .& ismissing.(b), missing, coalesce.(a, 0) .+ coalesce.(b, 0))
3-element Vector{Union{Missing, Int64}}:
3
1
missing
coalesce replaces missing with 0 in the above, but the result of that addition is only used if either of the two values being added is nonmissing.
Given your requirements I would recommend you to define your own custom addition that would implement the rule you want:
julia> ⨨(::Missing, ::Missing) = missing
⨨ (generic function with 1 method)
julia> ⨨(x, ::Missing) = x
⨨ (generic function with 2 methods)
julia> ⨨(::Missing, x) = x
⨨ (generic function with 3 methods)
julia> ⨨(x, y) = x + y
⨨ (generic function with 4 methods)
julia> [1, 2, missing, missing] .⨨ [10, missing, 30, missing]
4-element Vector{Union{Missing, Int64}}:
11
2
30
missing
In my example ⨨ can be typed by \plustrif<tab> (you could use any other symbol that is accepted as operator instead).
This is the most efficient way to achieve what you want.

Check for equivalence of string and symbol

I have a vector of symbols a_sym of length N_sym and a vector of strings a_str of length N_str
a_sym contains symbols at each index, such as :H₅B₂O₆⁻
a_str contains strings at each index, such as H₅B₂O₆⁻
I would like to check for equivalence of a_sym and a_str to see which index the equivalence occurs in each vector.
I have tried to implement a loop to check these two vectors:
E = zeros(Int64,N_sym)
for i in 1:N_str
for ii in 1:N_sym
if a_sym[ii] == a_str[i]
E[ii] = i
end
end
end
Where E is my attempt to map equivalent indices, but my loop never detects the strings to be equivalent. How could this be remedied? (and perhaps simplified?)
For example:
a_sym = [:H₃BO₃ ,:H₄BO₄⁻ ,:Li⁺ ,:H₅B₂O₆⁻, :H₄B₃O₇⁻]
where N_sym would be 5, and:
a_str = ["O⁻","H₃BO₃","H₄BO₄⁻","H₅B₂O₆⁻","H₄B₃O₇⁻","H₃B₃O₆"]
where N_str would be 6. I require the loop to check both vectors and map the indices when there is equivalnce, for instance the index of H₃BO₃ in a_sym would be 1, and its index in a_str would be 2.
I expect a vector E = [2, 3, 0, 4, 5] which is filled with the indices of a_str, and 0 if a_str does not contain a match for a_sym
Symbols and strings are never equivalent:
julia> :a == "a"
false
So you have to convert either to the other first. I would write your function as follows using the builtin findfirst:
julia> E = [findfirst(==(String(b)), a_str) for b in a_sym]
5-element Array{Union{Nothing, Int64},1}:
2
3
nothing
4
5
(Although, as Przemislaw notes, converting the strings to symbols would likely be more efficient.)
nothing is what findfirst returns if it does not find anything. You can convert this to a default by broadcasting something:
julia> something.(E, 0)
5-element Array{Int64,1}:
2
3
0
4
5

Transform nested array into new dimension

Given an array as follows:
A = Array{Array{Int}}(2,2)
A[1,1] = [1,2]
A[1,2] = [3,4]
A[2,1] = [5,6]
A[2,2] = [7,8]
We then have that A is a 2x2 array with elements of type Array{Int}:
2×2 Array{Array{Int64,N} where N,2}:
[1, 2] [3, 4]
[5, 6] [7, 8]
It is possible to access the entries with e.g. A[1,2] but A[1,2,2] would not work since the third dimension is not present in A. However, A[1,2][2] works, since A[1,2] returns an array of length 2.
The question is then, what is a nice way to convert A into a 3-dimensional array, B, so that B[i,j,k] refers the the i,j-th array and the k-th element in that array. E.g. B[2,1,2] = 6.
There is a straightforward way to do this using 3 nested loops and reconstructing the array, element-by-element, but I'm hoping there is a nicer construction. (Some application of cat perhaps?)
You can construct a 3-d array from A using an array comprehension
julia> B = [ A[i,j][k] for i=1:2, j=:1:2, k=1:2 ]
2×2×2 Array{Int64,3}:
[:, :, 1] =
1 3
5 7
[:, :, 2] =
2 4
6 8
julia> B[2,1,2]
6
However a more general solution would be to overload the getindex function for arrays with the same type of A. This is more efficient since there is no need to copy the original data.
julia> import Base.getindex
julia> getindex(A::Array{Array{Int}}, i::Int, j::Int, k::Int) = A[i,j][k]
getindex (generic function with 179 methods)
julia> A[2,1,2]
6
With thanks to Dan Getz's comments, I think the following works well and is succinct:
cat(3,(getindex.(A,i) for i=1:2)...)
where 2 is the length of the nested array. It would also work for higher dimensions.
permutedims(reshape(collect(Base.Iterators.flatten(A)), (2,2,2)), (2,3,1))
also does the job and appears to be faster than the accepted cat() answer for me.
EDIT: I'm sorry, I just saw that this has already been suggested in the comments.

Resources