Picking elements of an array

Hi,

Suppose I have an array a like the following

5Γ—2 Matrix{Float64}:
 2.0  1.0
 3.0  0.0
 4.0  1.0
 2.0  0.0
 4.0  1.0

The second column can only be 0 or 1. Now I want to pick the rows whose second element is 0 and store the first elements of these rows into a new array. In the example, I should have

b =[3.0,4.0]

How to achieve this goal?

Also, since my second column can only have 0 or 1. So in principle I can use Boolean variables. How to initiate my array such that the first column is 0(float64) and the second column is false (Bool).

Thanks

julia> a = [ 2.0  1.0
        3.0  0.0
        4.0  1.0
        2.0  0.0
        4.0  1.0]

julia> indices = findall(iszero,a[:,2])
2-element Vector{Int64}:
 2
 4

julia> b = a[indices,1]
2-element Vector{Float64}:
 3.0
 2.0

To have a table with different types for each column, you can use DataFrames from the DataFrames package:

julia>  using DataFrames 
  # you might need to install package if it isn't yet

julia> df = DataFrame(a1=[2.0, 3.0, 4.0, 2.0, 4.0],
  a2= [true, false, true, false, true])
5Γ—2 DataFrame                                               
 Row β”‚ a1       a2                                          
     β”‚ Float64  Bool      
─────┼────────────────
   1 β”‚     2.0   true
   2 β”‚     3.0  false
   3 β”‚     4.0   true                                       
   4 β”‚     2.0  false
   5 β”‚     4.0   true

julia> df.a1[(!).(df.a2)]
2-element Vector{Float64}:
 3.0
 2.0

The last line calculates the result (it uses ! and broadcasting . which require paranthesis because of parsing issues).

1 Like

Array comprehensions are pretty good for this purpose.

julia> M = Float64[2 1; 3 0; 4 1; 2 0; 4 1]
5Γ—2 Matrix{Float64}:
 2.0  1.0
 3.0  0.0
 4.0  1.0
 2.0  0.0
 4.0  1.0

julia> [first(r) for r in eachrow(M) if last(r) == 1]
3-element Vector{Float64}:
 2.0
 4.0
 4.0

julia> [first(r) for r in eachrow(M) if last(r) == 0]
2-element Vector{Float64}:
 3.0
 2.0

The simplest and most direct way is to use a vector of tuples: A = [(2.0, true), (3.0, false), ...)].
If you need convenient access to components of the array, StructArrays are a great fit. They have the same array interface, with extra functionality:

julia> A = [(2.0, true), (3.0, false), (4.0, true)] |> StructArray

julia> A.:1  # == [2.0, 3.0, 4.0]

julia> A.:2  # == [true, false, true]

julia> A[1]  # == (2.0, true)

# your b selection:
julia> b = A.:1[.!A.:2]
# or
julia> filter(x -> !x[2], A).:1

Everything here is efficient, and continues to works with all array/collection functions.

1 Like

Slightly off topic: I’ve seen this (!). idiom a lot, but .! works perfectly fine (with the dot in front, as with any operator):

julia> x = [false, true, false]
3-element Vector{Bool}:
 0
 1
 0

julia> .!x
3-element BitVector:
 1
 0
 1
1 Like

A tuple of arrays is also simple and direct:

A = (Float64[2, 3, 4, 2, 4], Bool[1, 0, 1, 0, 1])
([2.0, 3.0, 4.0, 2.0, 4.0], Bool[1, 0, 1, 0, 1])

julia> A[1][A[2]]
3-element Vector{Float64}:
 2.0
 4.0
 4.0

julia> A[1][.!A[2]]
2-element Vector{Float64}:
 3.0
 2.0

In fact you could also use a NamedTuple:

julia> NT = (floats = Float64[2, 3, 4, 2, 4], bools = Bool[1, 0, 1, 0, 1])
(floats = [2.0, 3.0, 4.0, 2.0, 4.0], bools = Bool[1, 0, 1, 0, 1])

julia> NT.floats[NT.bools]
3-element Vector{Float64}:
 2.0
 4.0
 4.0

julia> NT.floats[.!NT.bools]
2-element Vector{Float64}:
 3.0
 2.0
2 Likes

I don’t think the example in the original post has the correct result – if I (and several other posters) understand correctly, the result should be b=[3.0,2.0].

Other people’s notes about arrays of tuples or struct arrays are probably the better solutions. But to answer the original question directly, this looks like a good candidate for logical indexing:

julia> a = [2.0 1.0; 3.0 0.0; 4.0 1.0; 2.0 0.0; 4.0 1.0]
5Γ—2 Matrix{Float64}:
 2.0  1.0
 3.0  0.0
 4.0  1.0
 2.0  0.0
 4.0  1.0

julia> b = a[@view(a[:, 2]) .== 0, 1] # the @view() is unnecessary but gives slightly better performance
2-element Vector{Float64}:
 3.0
 2.0

Some of the other suggested methods (the comprehensions in particular) might be marginally more efficient than this, however.