I have an array A:
import numpy as np
A = np.array( [0, 0, 1, 1, 1, 0, 1, 1, 0 ,0, 1, 0] )
The length of consecutive '1s' would be:
output: [3, 2, 1]
with the corresponding starting indices:
idx = [2, 6, 10]
The original arrays are huge and I prefer a solution with less for-loop.
Edit (Run time):
import numpy as np
import time
A = np.array( [0, 0, 1, 1, 1, 0, 1, 1, 0 ,0, 1, 0] )
def LoopVersion(A):
l_A = len(A)
size = []
idx = []
temp_idx = []
temp_size = []
for i in range(l_A):
if A[i] == 1:
temp_size.append(1)
if not temp_idx:
temp_idx = i
idx.append(temp_idx)
else:
size.append( len(temp_size) )
size = [i for i in size if i != 0]
temp_size = []
temp_idx = []
return size, idx
Quang's solution:
def UniqueVersion(A):
_, idx, counts = np.unique(np.cumsum(1-A)*A, return_index=True, return_counts=True)
return idx, counts
Jacco's solution:
def ConcatVersion(A):
A = np.concatenate(([0], A, [0])) # get rid of some edge cases
starts = np.argwhere((A[:-1] + A[1:]) == 1).ravel()[::2]
ends = np.argwhere((A[:-1] + A[1:]) == 1).ravel()[1::2]
len_of_repeats = ends - starts
return starts, len_of_repeats
Dan's solution (works with special cases as well):
def structure(A):
ZA = np.concatenate(([0], A, [0]))
indices = np.flatnonzero( ZA[1:] != ZA[:-1] )
counts = indices[1:] - indices[:-1]
return indices[::2], counts[::2]
Run time analysis with 10000 elements:
np.random.seed(1234)
B = np.random.randint(2, size=10000)
start = time.time()
size, idx = LoopVersion(B)
end = time.time()
print ( (end - start) )
# 0.32489800453186035 seconds
start = time.time()
idx, counts = UniqueVersion(B)
end = time.time()
print ( (end - start) )
# 0.008305072784423828 seconds
start = time.time()
idx, counts = ConcatVersion(B)
end = time.time()
print ( (end - start) )
# 0.0009801387786865234 seconds
start = time.time()
idx, counts = structure(B)
end = time.time()
print ( (end - start) )
# 0.000347137451171875 seconds