Reputation: 384
I would like an efficient (vectorized) way of manipulating a matrix in julia into a new matrix where all non-zero elements are ones in the new matrix.
For example, I would like this matrix
0 3 6 8 0
7 0 2 0 1
0 4 9 1 0
to become
0 1 1 1 0
1 0 1 0 1
0 1 1 1 0
Upvotes: 4
Views: 843
Reputation: 4505
An alternative not yet mentioned is to use map
:
julia> x = [0 3 6 8 0
7 0 2 0 1
0 4 9 1 0]
3×5 Matrix{Int64}:
0 3 6 8 0
7 0 2 0 1
0 4 9 1 0
julia> map(!=(0), x)
3×5 Matrix{Bool}:
0 1 1 1 0
1 0 1 0 1
0 1 1 1 0
Note that !=(0)
is equivalent to y -> y != 0
.
As another answer shows, the result of broadcasting a Bool-valued function is a BitMatrix
. Using map
avoids this.
If you want a solution that produces "0" and "1" of the same type as the input:
julia> map(y -> ifelse(y == zero(y), one(y), zero(y)), x)
3×5 Matrix{Int64}:
1 0 0 0 1
0 1 0 1 0
1 0 0 0 1
julia> map(y -> ifelse(y == zero(y), one(y), zero(y)), Float64.(x))
3×5 Matrix{Float64}:
1.0 0.0 0.0 0.0 1.0
0.0 1.0 0.0 1.0 0.0
1.0 0.0 0.0 0.0 1.0
Upvotes: 3
Reputation: 69899
The simplest is to convert this matrix to a BitMatrix
matrix like this:
julia> x = [0 3 6 8 0
7 0 2 0 1
0 4 9 1 0]
3×5 Matrix{Int64}:
0 3 6 8 0
7 0 2 0 1
0 4 9 1 0
julia> x .!= 0
3×5 BitMatrix:
0 1 1 1 0
1 0 1 0 1
0 1 1 1 0
If you want the matrix to contain Int
values then you can do:
julia> Int.(x .!= 0)
3×5 Matrix{Int64}:
0 1 1 1 0
1 0 1 0 1
0 1 1 1 0
Finally if your 0
values have mixed types and you would want to preserve them "as is" then you can do:
julia> x = Real[0 3 6 8 UInt8(0)
7 0 2 0 1
0.0 4 9 1 0]
3×5 Matrix{Real}:
0 3 6 8 0x00
7 0 2 0 1
0.0 4 9 1 0
julia> @. ifelse(iszero(x), x, 1)
3×5 Matrix{Real}:
0 1 1 1 0x00
1 0 1 0 1
0.0 1 1 1 0
Apart from broadcasting you could use comprehension which also should be fast. Eg.
julia> [v == 0 ? v : 1 for v in x]
3×5 Matrix{Real}:
0 1 1 1 0x00
1 0 1 0 1
0.0 1 1 1 0
or e.g.
julia> [ifelse(v == 0, 0, 1) for v in x]
3×5 Matrix{Int64}:
0 1 1 1 0
1 0 1 0 1
0 1 1 1 0
Upvotes: 10