在列表中查找项目和重复项

时间:2017-03-03 10:08:47

标签: python list

我正在使用Python并考虑以下问题:给定一个列表,例如[1, 0, -2, 0, 0, 4, 5, 0, 3]多次包含整数0,我希望索引位于这些0和每一个,它出现在列表中的次数,直到出现不同的元素或列表结束。

给定l = [1, 0, -2, 0, 0, 4, 5, 0],函数将返回((1, 1), (3, 2), (7, 1))。结果是一个元组列表。元组的第一个元素是给定元素的索引(在列表中),第二个元素是在不同元素出现或列表结束之前重复的次数。

天真地,我会写这样的东西:

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

但是我想知道是否会有更好的(更短的?)方式做同样的事情。

5 个答案:

答案 0 :(得分:4)

不是最漂亮的,而是一个单行:

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

首先,itertools.groupby(enumerate(l), lambda x: x[1])将按enumerate(l)的第二项进行分组,但保留该项的索引。

然后[list(j) for i,j in itertools.groupby(enumerate(l), lambda x: x[1]) if i==0]将只保留0个值。

最后,需要最后一个列表理解,因为list(j)使用了itertools对象。

答案 1 :(得分:3)

另一个groupby的oneliner,没有使用中间列表:

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

在上面enumerate将返回(index, value)个元组,然后按值对其进行分组。 groupby返回(key, iterable)个元组,如果key为非零,则该组将被丢弃。对于保留的组next用于拉出组中的第一个项目并从那里获取索引,而其余项目由给予sum的生成器表达式处理以获得计数。

答案 2 :(得分:1)

一个选项是让itertools.groupby根据条件为您分割列表:

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

请注意,当目标元素不在列表中时,这将返回空列表。

答案 3 :(得分:1)

我就是这样做的

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

答案 4 :(得分:1)

另一种解决方案,使用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)

该行

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

计算从当前位置到右边的零的数量。

虽然足够清楚,但这个解决方案的缺点是它在处理之前需要整个列表。