2017-12-12 89 views
7

Mam listę sygnałów (reprezentujących kolejne MESURES):lista Python zachować wartość tylko wtedy równa n poprzedników

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

uważam sygnał ważna tylko wtedy równa poprzednich n MESURES.

Np. jeśli weźmiemy pod uwagę tylko 2 komunikaty do sprawdzania poprawności (n=2), pierwsze sygnały czasowe zmieniają się z 0 na 1, uważamy, że nadal jest 0, ale następna, jeśli jest to 1 ponownie, to uważamy, że nadal jest poprawna i sprawiają, że 1. Wtedy potrzebowalibyśmy 2 mesures z 0, aby zmienić go na 0, itd ... Tutaj sygnały są 0 i 1 dla uproszczenia, ale w mojej aplikacji mogą to być inne liczby całkowite.

Pożądany wyjściowa:

# 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] 

Szukałem o pythonesque sposób jedną wkładką robi to, ale nie wydaje się znaleźć pożądany wynik. Próbowałem coś wzdłuż linii:

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: Jestem otwarty na numpy jeśli to sprawia, że ​​łatwiej, gdyż już importowane.

+0

Czy pożądany wynik dla n = 2 jest poprawny? Czy opierasz swoje wyniki tylko na zmierzonych wartościach lub na już "skorygowanych" poprzednich wartościach? – voiDnyx

+0

Tak, dla n = 2 potrzebuję dwóch kolejnych 1 lub 0 do rozważenia przejścia na 1 lub 0. Jeśli nie mam dwóch kolejnych, to zachowuję poprzednio już zatwierdzoną wartość. Stąd pożądane wyjście dla n = 2. – Fredovsky

Odpowiedz

5

Nie sądzę, że istnieje dobry sposób, aby uczynić to zrozumieniem dla jednego liniowca/listy. Chociaż można użyć all z plasterkiem listy, aby zobaczyć, czy wartość jest taka sama jak wcześniej wartości n, nie widzę dobrego sposobu na określenie, która powinna być ostatnią prawidłową wartością na wypadek, gdyby nie była.

Zamiast tego można użyć dobrego-old "many-linie" dla pętli:

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) 

Następnie res jest [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0]


Alternatywnie, nieco krótsza, używając itertools.groupby; Rezultat jest taki sam:

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) 
+2

Dodatek: Jak zawsze, jeśli potrzebujesz rozwiązania jednoliniowego, po prostu spraw, aby był on funkcją. ;-) –

+0

Trochę krótszy i może prostszy: https://ideone.com/vtjVUW –

+1

Oh, * znacznie * krótszy/prostszy: https://ideone.com/cgEnpu –

2
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] 

Ale rozważyć to i myślę, że podejście czysto iteracyjny (mniej pythonowy) jest prawdopodobnie bardziej efektywne. Po zakończeniu mojego nowego podejścia, teraz myślę, że jest to ten sam pomysł, co @tobias_k już zaimplementowane w jego odpowiedzi:

+0

Dlaczego "dzwonek"? Dlaczego nie tylko kawałek listy? –

+0

Ponieważ tworzenie plasterków jest prawdopodobnie bardziej kosztowne niż użycie bufora pierścieniowego. Zależy od wdrożenia, na którym nie chcę polegać. – Alfe

+0

Ważny punkt, ale ogólna złożoność jest nadal "O (len (lst) * n)" –