2017-03-03 17 views
6

Tôi đang làm việc bằng Python và xem xét vấn đề sau: với một danh sách, chẳng hạn như [1, 0, -2, 0, 0, 4, 5, 0, 3] chứa số nguyên 0 nhiều lần, tôi muốn có chỉ số tại số 0 và cho mỗi , số lần nó xuất hiện trong danh sách cho đến khi một phần tử khác xuất hiện hoặc danh sách kết thúc.Tìm các mục và lặp lại trong danh sách

Cho l = [1, 0, -2, 0, 0, 4, 5, 0], hàm sẽ trả lại ((1, 1), (3, 2), (7, 1)). Kết quả là một danh sách các bộ dữ liệu. Phần tử đầu tiên của tuple là chỉ mục (trong danh sách) của phần tử đã cho và phần tử thứ hai là số lần nó được lặp lại cho đến khi một phần tử khác xuất hiện hoặc danh sách kết thúc.

ngây thơ, tôi sẽ viết một cái gì đó như thế này:

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 

Nhưng tôi đã tự hỏi liệu sẽ có một đẹp hơn (ngắn hơn?) Cách để làm điều tương tự.

Trả lời

1

Một lựa chọn là để cho itertools.groupby chia tay danh sách cho bạn dựa trên điều kiện:

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

Lưu ý rằng điều này sẽ chỉ trả lại danh sách trống khi các yếu tố mục tiêu không có trong danh sách.

4

Không phải là đẹp, nhưng một lớp lót:

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

Thứ nhất, itertools.groupby(enumerate(l), lambda x: x[1]) chí nhóm theo mục thứ hai của enumerate(l), nhưng giữ chỉ số của mặt hàng đó.

Sau đó, [list(j) for i,j in itertools.groupby(enumerate(l), lambda x: x[1]) if i==0] sẽ chỉ giữ giá trị 0.

Cuối cùng, việc hiểu danh sách cuối cùng là cần thiết vì list(j) tiêu thụ đối tượng itertools.

+0

Thật vậy, nó có thể được thực hiện trong một dòng với 'itertools'.Tôi sẽ nhìn vào thư viện này. Cảm ơn bạn ! – Odile

1

Đây là cách tôi sẽ làm điều này

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

oneliner Một với groupby, mà không sử dụng danh sách trung gian:

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

Trong trên enumerate sẽ trở lại (index, value) tuples mà sau đó được nhóm lại theo giá trị. groupby trả về (key, iterable) bộ dữ liệu và nếu khóa không đồng bộ thì nhóm sẽ bị hủy. Đối với các nhóm được giữ next được sử dụng để lấy ra mục đầu tiên trong nhóm và lấy chỉ mục từ đó trong khi phần còn lại của các mục được xử lý bằng biểu thức máy phát được gán cho sum để nhận số đếm.

1

Một giải pháp khác, sử dụng 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) 

Dòng

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

đếm số lượng zero có từ vị trí hiện tại ở bên phải.

Mặc dù đủ rõ ràng, bất lợi của giải pháp này là nó cần toàn bộ danh sách trước khi xử lý.

Các vấn đề liên quan