Filtering using conditional evaluation (&&) - julia

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]

Related

Convert a Set to an Array in Julia

How can I convert a Set to an Array in Julia?
E.g. I want to transform the following Set to an Array.
x = Set([1,2,3])
x
Set{Int64} with 3 elements:
2
3
1
The collect() function can be used for this. E.g.
collect(x)
3-element Vector{Int64}:
2
3
1
Notice, however, that the order of the elements has changed. This is because sets are unordered.
You can also use the splat operator on sets:
julia> [x...]
3-element Vector{Int64}:
2
3
1
However, this is slower than collect.
You can use [ ] to create an array.
x = Set([1,2,3])
y = [a for a in x]
y
2
3
1
typeof(y)
Vector{Int64} (alias for Array{Int64, 1})
You can use a comprehension:
x = Set(1:5)
#time y = [i for i in x]
> 0.000006 seconds (2 allocations: 112 bytes)
typeof(y)
> Vector{Int64} (alias for Array{Int64, 1})

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 do you access multi-dimension array by N array of index element-wise?

Suppose we have
A = [1 2; 3 4]
In numpy, the following syntax will produce
A[[1,2],[1,2]] = [1,4]
But, in julia, the following produce a permutation which output
A[[1,2],[1,2]] = [1 2; 3 4]
Is there a concise way to achieve the same thing as numpy without using for loops?
To get what you want I would use CartesianIndex like this:
julia> A[CartesianIndex.([(1,1), (2,2)])]
2-element Vector{Int64}:
1
4
or
julia> A[[CartesianIndex(1,1), CartesianIndex(2,2)]]
2-element Vector{Int64}:
1
4
Like Bogumil said, you probably want to use CartesianIndex. But if you want to get your result from supplying the vectors of indices for each dimensions, as in your Python [1,2],[1,2] example, you need to zip these indices first:
julia> A[CartesianIndex.(zip([1,2], [1,2]))]
2-element Vector{Int64}:
1
4
How does this work? zip traverses both vectors of indices at the same time (like a zipper) and returns an iterator over the tuples of indices:
julia> zip([1,2],[1,2]) # is a lazy iterator
zip([1, 2], [1, 2])
julia> collect(zip([1,2],[1,2])) # collect to show all the tuples
2-element Vector{Tuple{Int64, Int64}}:
(1, 1)
(2, 2)
and then CartesianIndex turns them into cartesian indices, which can then be used to get the corresponding values in A:
julia> CartesianIndex.(zip([1,2],[1,2]))
2-element Vector{CartesianIndex{2}}:
CartesianIndex(1, 1)
CartesianIndex(2, 2)

Returned array is unexpected

The following lines
s = [1 2 5 7 3 3]
index=findall(x -> (x < 7 & x > 3), s)
[idx[2] for idx in index]
returns
0-element Array{Int64,1}
when there is a 5 in s. What is going wrong here?
& is bit-wise AND operator and the operator precedence kicks in here. The logical AND operator in Julia is &&.
You can use parenthesis to make your expression correct for your purpose, i.e. (x > 7) & (x > 3), though I would not recommend this one.
You should instead use logical AND operator &&, or perhaps better directly write what you would write on a paper i.e. 3 < x < 7. All of these methods work.
s = [1 2 5 7 3 3]
index=findall(x -> 3 < x < 7, s)
[idx[2] for idx in index]
& operates on bits and the logical and is &&.
For what you want to do just use filter:
julia> filter(x -> 7 > x > 3, s)
1-element Array{Int64,1}:
5

indices of unique elements of vector in Julia

How to get indexes of unique elements of a vector?
For instance if you have a vector v = [1,2,1,3,5,3], the unique elements are [1,2,3,5] (output of unique) and their indexes are ind = [1,2,4,5]. What function allows me to compute ind so that v[ind] = unique(v) ?
This is a solution for Julia 0.7:
findfirst.(isequal.(unique(x)), [x])
or similar working under Julia 0.6.3 and Julia 0.7:
findfirst.(map(a -> (y -> isequal(a, y)), unique(x)), [x])
and a shorter version (but it will not work under Julia 0.7):
findfirst.([x], unique(x))
It will probably not be the fastest.
If you need speed you can write something like (should work both under Julia 0.7 and 0.6.3):
function uniqueidx(x::AbstractArray{T}) where T
uniqueset = Set{T}()
ex = eachindex(x)
idxs = Vector{eltype(ex)}()
for i in ex
xi = x[i]
if !(xi in uniqueset)
push!(idxs, i)
push!(uniqueset, xi)
end
end
idxs
end
Another suggestion is
unique(i -> x[i], 1:length(x))
which is about as fast as the function in the accepted answer (in Julia 1.1), but a bit briefer.
If you don't care about finding the first index for each unique element, then you can use a combination of the unique and indexin functions:
julia> indexin(unique(v), v)
4-element Array{Int64,1}:
3
2
6
5
Which gets one index for each unique element of v in v. These are all in base and works in 0.6. This is about 2.5 times slower than #Bogumil's function, but it's a simple alternative.
A mix between mattswon and Bogumił Kamiński answers (thanks !):
uniqueidx(v) = unique(i -> v[i], eachindex(v))
eachindex allows to work with any kind of array, even views.
julia> v = [1,2,1,3,5,3];
julia> uniqueidx(v)
4-element Vector{Int64}:
1
2
4
5
julia> v2 = reshape(v, 2, 3)
2×3 Matrix{Int64}:
1 1 5
2 3 3
julia> subv2 = view(v2, 1:2, 1:2)
2×2 view(::Matrix{Int64}, 1:2, 1:2) with eltype Int64:
1 1
2 3
julia> uniqueidx(subv2)
3-element Vector{CartesianIndex{2}}:
CartesianIndex(1, 1)
CartesianIndex(2, 1)
CartesianIndex(2, 2)

Resources