Replacing only zeros in an array with another array's values in Julia

Viewed 645

I am trying to replace an array with another array, but only in places where the original array is zero. These arrays are equal in dimensions.

Array1 = [0, 2, 4, 2, 5, 0, 0, 2, 5]
Array2 = [1, 2, 3, 4, 5, 6, 7, 8, 9]

I am currently trying to use the code below to superimpose array2 into array 1 where array1's values are equal to zero.

Array1[Array1 .== 0] .= Array2

From this I was hoping to get the following...

Array1 = [1, 2, 4, 2, 5, 6, 7, 2, 5]

but instead I get an error...

ERROR: DimensionMismatch("array could not be broadcast to match destination")

Is there a nice way to do this without looping through each list/array one element at a time? I am working with really large arrays and don't know if that would be too slow. Any help is appreciated.

2 Answers

This can be done easily almost the way you have it:

Array1[Array1 .== 0] .= Array2[Array1 .== 0]

The part Array1 .== 0 is creating an array of zeros and ones that has the same length as the original one. Zeros in the places where the condition is not met and ones in the places where the condition is met.

When you do something like:

Array1 .= Array2

You are telling julia to copy Array2 elementwise into Array1, this works because Array1 and Array2 have the same length. But when you try to do

Array1[Array1 .== 0] .= Array2

You are telling to put every element of Array2 into a subset of elements in Array1 (the ones that satisfy your condition). This fail because the arrays are not of the same length. If you instead do

Array1[Array1 .== 0] .= Array2[Array1 .== 0] 

You are now telling "copy all the elements of Array2 in the indices where Array1 satisfy the condition, into the same place in Array1". These two now are of the same length.

Note, however, that in julia for loops are fast, so you will be fine if you use them.

Instead of indexing, you could also broadcast a function over the values. Here I've used 100*Array2 for the replacement values just so you can see which were changed, and @. is equivalent to writing out Array1 .= ifelse.(Array1 .== 0, 100 .* etc. but ensures you won't miss a dot.

julia> @. Array1 = ifelse(Array1==0, 100*Array2, Array1)
9-element Vector{Int64}:
 100
   2
   4
   2
   5
 600
 700
   2
   5

This is likely to be more efficient, as each Array1 .== 0 makes a boolean array, and Array2[Array1 .== 0] makes a temporary copy of this data.

Related