Python list only retains value if it equals n predecessors

I have a list of signals (representing consecutive measurements):

signals = [0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0] 

I consider a signal that is valid only if it is equal to the previous n measures.

Eg. if we consider only 2 dimensions for validation (n=2) , then the first time signals turn from 0 to 1, we consider it to be 0, but the next measurement, if it is 1 again, we believe that it is still valid and does its 1. Then we need 2 measurements 0 to turn it back to 0, etc. Here the signals are 0 and 1 for simplicity, but in my application they can be other integers.

Required Conclusion:

 # For n = 2: valid_s = [0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0] # For n = 3: valid_s = [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0] # For n = 4: valid_s = [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0] 

I was looking for a Python single-line way to do this, but couldn't find the result I needed. I tried something line by line:

 S = signals # For n = 2 [S[i] if S[i] == S[i-1] else S[i-2] for i, _ in enumerate(S)] # gives [0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0] # For n = 3 [S[i] if S[i] == S[i-1] == S[i-2] else S[i-3] for i, _ in enumerate(S)] # gives [0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0] 

Edit: I am open to numpy if it makes importing it easier.

+7
python
source share
2 answers

I don't think there is a good way to do this with a single line / list. While you can use all with a list fragment to find out if this value matches n values, I don’t see a good way to determine what the last real value should be if it is not.

Instead, you can use the old "multi-line line" for the loop:

 signals = [0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0] n = 3 last_valid = 0 current = None repeated = 0 res = [] for s in signals: if s == current: repeated += 1 else: repeated = 1 current = s if repeated >= n: last_valid = s res.append(last_valid) 

Then res is [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0]


Alternatively, a little shorter using itertools.groupby ; The result is the same:

 last_valid = 0 res = [] for k, g in itertools.groupby(signals): m = len(list(g)) if m >= n: res.extend([last_valid] * (n-1) + [k] * (m-n+1)) last_valid = k else: res.extend([last_valid] * m) 
+5
source share
 signal = [0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0] def each(signal, n): p = 0 ring = [ signal[0] ] * (n-1) v = None for x in signal: if v is None or all(q == x for q in ring): v = x yield v ring[p] = x p = (p+1) % (n-1) list(each(signal, 2)) [0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0] 

But I revised this and thought that a pure iterative (less Pythonic) approach is probably more efficient. After completing my new approach, I now think that this is the same idea as @tobias_k already implemented in his answer:

 def each(signal, n): current = signal[0] next = None for v in signal: if v != current: if v == next: next_count += 1 else: next_count = 1 next = v if next_count >= n: current = v yield current 
+2
source share

All Articles