2016-06-11 11 views
5

Tak na przykład, jeśli mam listZnajdź liczbę kolejnych elementów, które są takie same, zanim zmieni

a = [1,1,1,2,2] 
b = [1,1,2,2,2] 
c = [2,1,1,1,1] 

chciałbym uzyskać najdłuższą passę pierwszy element na liście, więc na przykład a dałoby 3, b dałoby 2, a c dałoby 1. Wiem, że mógłbym utworzyć pętlę while i policzyć pas w ten sposób, ale zastanawiałem się, czy istnieje bardziej elegancki sposób na zrobienie tego?

+0

jeśli chcesz policzyć wszystkie wystąpienia pierwszego elementu można użyć a.count ([0]) – amitnair92

+0

Wyrażenie „najdłuższy«smuga * *»pierwszego elementu” jest bit dwuznaczny: czy odpowiedź na '[1,1,1,2,2,1,1,1,1]' wynosi 3 lub 4. – ninjagecko

Odpowiedz

6

mógłby zrobić coś takiego:

numStreak = ([a[0] == n for n in a]+[False]).index(False) 

(w tym także dba o to, czy wszystkie elementy są jak pierwszy element, indeks nie zwróci poprawną wartość)

UPDATE: bardziej wydajny (ale mniej elegancki?) wersja

from itertools import takewhile 
len([1 for _ in takewhile(lambda x:x==a[0], a)]) 

lub nieco lepsza (UPDATE 2) @ vaultah za sugestia:

sum(1 for _ in takewhile(lambda x:x==a[0], a)) 
+2

To jest bardzo sprytne, ale mnie to zasmuca, że ​​iteruje na całej liście, nawet jeśli długość wynosi 1. –

+0

Dodałem bardziej wydajną, ale może nieco mniej elegancką wersję: – DomTomCat

+0

Powinno być 'sumą (1 dla _ w takewhile (lambda x: x == a [0], a))' – vaultah

3

Można użyć GroupBy i podsumować ile przedmioty są w pierwszej grupie dla każdego:

a = [1,1,1,2,2] 
b = [1,1,2,2,2] 
c = [2,1,1,1,1] 

from itertools import groupby 

for l in [a,b,c]: 
    print(sum(1 for _ in next(groupby(l), [[], []],)[1])) 

lub używając takewhile:

from itertools import takewhile 

for l in [a, b, c]: 
    print(sum((1 for _ in takewhile(lambda x: x == l[0], l)))) 

Jeśli dane jest zawsze lista, krotka etc. W grupie groupby można sprawdzić wartość falsey w przeciwieństwie do ustawienia domyślnego w next(..:

for l in [a, b, c]: 
    print(sum(1 for _ in next(groupby(l))[1]) if l else 0) 
+0

Nie bardzo rozumiem '[[], []]' część. Co to robi? – DSM

+0

@DSM, jeśli pusta iteracja została przekazana, otrzymasz komunikat "StopIteration" –

+0

Ah, dobra, widzę, co robisz teraz. Jeśli wiemy, że mamy sekwencje, prawdopodobnie dodaję po prostu 'if l else 0' na końcu, ale to nie poradzi sobie z przypadkiem ogólnej iteracji. – DSM

0

Można użyć numpy:

>>> import numpy as np 
>>> a = [1,1,1,2,2] 
>>> b = [1,1,2,2,2] 
>>> c = [2,1,1,1,1] 
>>> def runs(data): 
... return np.split(data, np.where(np.diff(data) != 0)[0]+1) 
... 
>>> for e in a,b,c: 
... runs(np.array(e)) 
... 
[array([1, 1, 1]), array([2, 2])] 
[array([1, 1]), array([2, 2, 2])] 
[array([2]), array([1, 1, 1, 1])] 

Następnie wystarczy wziąć długość pierwszego biegu:

>>> for e in a,b,c: 
... len(runs(np.array(e))[0]) 
... 
3 
2 
1 

Lub, w Pythonie, wystarczy użyć while pętlę:

>>> def r(a): 
... i=1 
... while a[0]==a[i]: i+=1 
... return i 
... 
>>> r(a) 
3 
>>> r(b) 
2 
>>> r(c) 
1 
1

Jedna wkładka do drogi? Wycelować ...

a = [5,5,5,5,8] 
list(np.ediff1d(a)).count(0)+1 
>>> 4