bambi
bambi

Reputation: 384

Create new matrix with all non-zero elements set to ones (julia)

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

Answers (2)

Gus
Gus

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

Bogumił Kamiński
Bogumił Kamiński

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

Related Questions