Reputation: 778
I'm using Numpy and SciPy. I have two arrays, the first of which is binary, the second a consecutive range of natural numbers from a
to b
e.g.
mask = np.array([1, 1, 1, 1, 0, 0, 1, 0]) # length of 8, with 5 ones and 3 zeros
vals = np.array([2, 3, 4, 5, 6, 7, 8, 9]) # length of 8, only first 5 values will be used in this case - corresponding to the 5 ones in the first array
I'd like to essentially replace the 1s in the first array with the values in the second (kept in order) e.g. the required result in this example scenario would be:
result = [2,3,4,5,0,0,6,0]
I've already tried different methods with NumPy masked arrays and the vectorise function. My current solution is below, but in order to maintain the state, I've had to introduce a global variable!
global count
count = 0
def func(a,b):
global count
if a ==1:
return b - count
else:
count +=1
return 0
v_func = np.vectorize(func)
result = v_func(mask, vals)
print result
Is there a more elegant way of doing this, (ideally using NumPy)?
(Side note, the real arrays I'm working with are very large and so my solution needs to be sensitive to the amount of memory consumed - obviously I can convert to sparse arrays, but I've still hit memory errors a couple of times trying to find different solutions.)
Upvotes: 1
Views: 286
Reputation: 4520
Here is a one liner, though I must say it is not an optimized way and not very elegant. But you can examine it for practice purposes.
a = [1, 1, 1, 1, 0, 0, 1, 0]
b = [2, 3, 4, 5, 6, 7, 8, 9]
c = [b[sum(a[:i])] if a[i] else 0 for i in range(len(a))]
print c
# Gives [2, 3, 4, 5, 0, 0, 6, 0]
Upvotes: 2
Reputation: 114946
Here's one way:
In [15]: result = np.zeros_like(vals)
In [16]: result[mask > 0] = vals[:mask.sum()]
In [17]: result
Out[17]: array([2, 3, 4, 5, 0, 0, 6, 0])
Upvotes: 2