0

I have NumPy N-dimensional bool array b.

It was converted to indices of True values by i = np.nonzero(b).

What is the shortest one-liner to convert i back to b.

Of cause it can be done multi-line as:

b = np.zeros(b_shape, dtype = np.bool_)
b[i] = True

Obviously one-liner can be achieved by ;-concatenation of lines, or some other tuple/lambda magic, or by defining a separate function.

But what I really want is to find some built-in NumPy function like b = np.indices_to_bools(i, shape = b_shape) or to figure out some beautiful superposition of several built-in functions. So that solution can be embedded as a part of a bigger complex expression.

Also I want solution to be as efficient (CPU/RAM-wise) or almost as efficient as those two lines of code above. Not just any inefficient one-liner.

Arty
  • 14,883
  • 6
  • 36
  • 69
  • Sounds like a job for just writing your own helper function. – user2357112 Nov 01 '20 at 13:13
  • @user2357112supportsMonica Also what is interesting is that I didn't find in numpy any way (besides defining a function) of copy-index-assign operation like `a1 = np.copy_index_assign(a2, indices, a3)`. Seems also like a common at least for me operation (copy-index-assign). – Arty Nov 01 '20 at 13:17
  • You are trying to apply foreign notions of code beauty to `numpy`. I would call that kind of superposition 'chaining', and `numpy` isn't particularly keen on that. Creating an array, and doing one or more (masked) assignments is a rather routine `numpy` operation, And too general to force into the chained mold. Look at the `np.delete` code for an example of its use. – hpaulj Nov 01 '20 at 16:07

1 Answers1

0

It can be done keep in mind that it is not that optimal but for arrays of 100K elements the difference will be ok trade for the oneliner.

b = np.in1d(np.arange(b.size), np.ravel_multi_index(i, dims=b.shape))

It is significantly easier to do this for 1d arrays, the code above is for N dimensions

jimakr
  • 574
  • 3
  • 7
  • Is it correct that `np.in1d` checks all elements of `np.arange(b.size)`? Then if `b.size` is 1M and `i` contains just 1K indices then complexity will be at least `1M * log(1K)` if to use binary search. Seems like to much compared to fast `b[i] = True` doing `1K` operations. – Arty Nov 03 '20 at 17:05
  • @Arty yeah it's not efficient for sure the fastest method will always probably be the 2 line solution since it's the intended way. I added a different approach that will run in almost the same time as the 2 lines but with extra ram – jimakr Nov 03 '20 at 17:45
  • I think your solution with addition doesn't work, because `np.ones(b.shape)[i]` gives same result as just `np.ones((i.size,))`, just 1D array having that many ones as there are indices, then you add this 1D array of ones to another 1D array of zeros of different length, this code will throw an error due to non-equal sizes. – Arty Nov 03 '20 at 17:52
  • Yeah solution2 didn't work tested it wrongly, but solution 1 still does and while inefficient it's the trade off for the oneliner – jimakr Nov 03 '20 at 18:08
  • It can be done(tested) in a very hacky way exploiting the fact b is already declared and that numpy trick allows to run 2 commands inside of chains but i should not realy be used just go with 2 lines – jimakr Nov 03 '20 at 18:20