Search for items and repetitions in a list

I work in Python and consider the following problem: given a list, for example [1, 0, -2, 0, 0, 4, 5, 0, 3] , which contains the integer 0 several times, I would like to have indices in these 0 and for each of them, the number of times it appears in the list until another item appears or the list ends.

Given l = [1, 0, -2, 0, 0, 4, 5, 0] , the function will return ((1, 1), (3, 2), (7, 1)) . The result is a list of tuples. The first element of the tuple is the index (in the list) of this element, and the second is the number of repetitions until another element appears or the list ends.

Naively, I would write something like this:

 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 

But I was wondering if there would be a nicer (shorter?) Way to do the same.

+6
source share
5 answers

Not the most beautiful, but one-line:

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

First, itertools.groupby(enumerate(l), lambda x: x[1]) will be grouped by the second element enumerate(l) , but will keep the index of the element.

Then [list(j) for i,j in itertools.groupby(enumerate(l), lambda x: x[1]) if i==0] will only store the values ​​0.

Finally, a final understanding of the list is necessary because list(j) consumes the itertools object.

+4
source

Another oneliner with groupby , without using intermediate lists:

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

In the above, enumerate will return tuples (index, value) , which are then grouped by value. groupby returns (key, iterable) tuples, and if the key is nonzero, the group is discarded. For saved groups, next used to pull the first element in the group and get the index from there, while the remaining elements are processed by the generator expression specified by sum to get the count.

+3
source

One option is to let itertools.groupby split the list for you based on the condition:

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

Note that this will simply return an empty list if the target element is not in the list.

+1
source

This is how i would do it

 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)) 
+1
source

Another solution using 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) 

Line

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

counts the number of zeros from the current position to the right.

Despite the fact that it is clear enough, the disadvantage of this solution is that before it is processed, it needs the whole list.

+1
source

Source: https://habr.com/ru/post/1015435/


All Articles