2017-03-03 19 views
6

Pracuję w Pythonie i biorąc pod uwagę następujący problem: biorąc pod uwagę listę, taką jak [1, 0, -2, 0, 0, 4, 5, 0, 3], która zawiera liczbę całkowitą 0 wiele razy, chciałbym mieć indeksy na tych 0 i dla każdego , ile razy pojawi się na liście, aż pojawi się inny element lub lista się skończy.Znajdź pozycje i powtórzenia w liście

Po otrzymaniu l = [1, 0, -2, 0, 0, 4, 5, 0] funkcja powróci ((1, 1), (3, 2), (7, 1)). Wynikiem jest lista krotek. Pierwszym elementem krotki jest indeks (na liście) danego elementu, a drugi to liczba powtórzeń, aż pojawi się inny element lub lista się kończy.

naiwnie, chciałbym napisać coś takiego:

def myfun(l, x): 
    if x not in l: 
     print("The given element is not in list.") 
    else: 
     j = 0 
     n = len(l) 
     r = list() 
     while j <= (n-2): 
      count = 0 
      if l[j] == x: 
       while l[j + count] == x and j <= (n-1): 
        count +=1 
       r.append((j, count)) 
       j += count 
      else: 
       j += 1 
     if l[-1] == x: 
      r.append((n-1, 1)) 
     return r 

Ale zastanawiałem się, czy nie byłoby ładniej (krótszy?) Sposób robi to samo.

Odpowiedz

1

Jedną z opcji jest umożliwienie itertools.groupby podzielić listę na Ciebie na podstawie warunku:

import itertools 

def myfun(l, x): 
    result = [] 
    currentIdx = 0 
    # group by condition: 
    for isZero, group in itertools.groupby(i==x for i in l): 
     groupLen = len(list(group)) 
     if isZero: result.append((currentIdx, groupLen)) 
     currentIdx += groupLen 
    return result 

l=[1, 0, -2, 0, 0, 4, 5, 0] 
print(myfun(l, 0)) 

Należy pamiętać, że będzie to po prostu zwróci pustą listę, gdy element docelowy nie znajduje się na liście.

4

nie najładniejsza, ale jedno-liner:

>>> import itertools 
>>> l=[1, 0, -2, 0, 0, 4, 5, 0] 
>>> [(k[0][0],len(k)) for k in [list(j) for i,j in itertools.groupby(enumerate(l), lambda x: x[1]) if i==0]] 
[(1, 1), (3, 2), (7, 1)] 

Najpierw itertools.groupby(enumerate(l), lambda x: x[1]) woli przez drugą grupę pozycji enumerate(l), ale utrzymać indeks elementu.

Następnie [list(j) for i,j in itertools.groupby(enumerate(l), lambda x: x[1]) if i==0] zachowa tylko wartości 0.

Wreszcie, potrzebne jest zrozumienie ostatniej listy, ponieważ list(j) zużywa obiekt itertools.

+0

Rzeczywiście, można to zrobić w jednej linii za pomocą 'itertools'.Zajrzę do tej biblioteki. Dziękuję Ci ! – Odile

1

ten sposób chciałbym zrobić to

l=[1, 0, -2, 0, 0, 4, 5, 0] 
lis=[] 
t=0 
for m in range(len(l)): 
    if l[m]==0: 
     if t==0: 
      k=m 
      j=1 
      t=1 
     else: 
      j=j+1 
      t=1 
     if m==len(l)-1: 
      lis.append((k,j)) 
    else: 
     if t==1: 
      t=0 
      lis.append((k,j)) 
3

Another oneliner z groupby, bez korzystania z list pośrednich:

>>> from itertools import groupby 
>>> l = [1, 0, -2, 0, 0, 4, 5, 0, 3] 
>>> [(next(g)[0], 1 + sum(1 for _ in g)) for k, g in groupby(enumerate(l), key=lambda x: x[1]) if k == 0] 
[(1, 1), (3, 2), (7, 1)] 

W powyższym enumerate powróci (index, value) krotki, które następnie są pogrupowane według wartości. groupby zwraca (key, iterable) krotek i jeśli klucz jest niezerowy, grupa jest odrzucana. W utrzymywanych grupach next służy do wyciągania pierwszego elementu z grupy i pobierania indeksu z tego miejsca, podczas gdy pozostałe elementy są przetwarzane przez wyrażenie generatora podane do sum w celu uzyskania liczby.

1

Innym rozwiązaniem, używając itertools.takewhile:

from itertools import takewhile 

L = [1, 0, -2, 0, 0, 4, 5, 0] 

res = [] 
i = 0 
while i < len(L): 
    if L[i] == 0: 
     t = len(list(takewhile(lambda k: k == 0, L[i:]))) 
     res.append((i, t)) 
     i += t 
    else: 
     i += 1 

print(res) 

Linia

t = len(list(takewhile(lambda k: k == 0, L[i:]))) 

liczy się liczba zer istnieją od aktualnego położenia po prawej stronie.

Chociaż wystarczająco jasne, wadą tego rozwiązania jest to, że potrzebuje całej listy przed jej przetworzeniem.

Powiązane problemy