列表python中的计数列表出现

时间:2017-02-25 13:04:42

标签: python

我想计算一个大清单包含特定顺序元素的次数。例如,如果我有元素[1,2,3,4,5,1,2,3,4,5,1,2,3,4,5,1,2,3,4,5],并且我想知道[1,2,3]彼此相邻的次数(在这种情况下答案是4)。

我正在考虑检查数字'3'的索引(所以当前它会返回[2,7,12,17]。然后我会迭代该列表,在列表中描述的位置获取元素并检查前面的两个位置如果它们匹配'1'和'2',那么将1添加到计数器并继续寻找。我相信这个解决方案效率不高并且看起来不太好,是否会有更好的解决方案?

6 个答案:

答案 0 :(得分:5)

这是一个通用的解决方案,适用于任何大小的子序列和任何类型的元素。它也非常节省空间,因为它只在迭代器上运行。

from itertools import islice

def count(lst, seq):
    it = zip(*(islice(lst, i, None) for i in range(len(seq))))
    seq = tuple(seq)
    return sum(x == seq for x in it)
In [4]: count(l, (1, 2, 3))
Out[4]: 4

我们的想法是在len(seq)上创建宽度为lst的滑动窗口迭代器,并计算等于tuple(seq)的元组数。这意味着count也会计算重叠匹配:

In [5]: count('aaa', 'aa')
Out[5]: 2

答案 1 :(得分:2)

对于整数列表,您可以转换为字符串,然后使用count方法:

>>> x = [1,2,3,4,5,1,2,3,4,5,1,2,3,4,5,1,2,3,4,5]
>>> y = [1,2,3]
>>> s = ',' + ','.join(str(i) for i in x) + ','
>>> t = ',' + ','.join(str(i) for i in y) + ','
>>> s.count(t)
4

如果列表中的项目包含包含逗号的字符串,则此方法可能会失败(如@schwobaseggl在注释中指出的那样)。您需要选择一个已知不会出现在任何字符串中的分隔符,或者采用一种完全不同的方法,该方法不会缩减为字符串count方法。

On Edit :我添加了@Rawing建议的解决方案,以解决@tobias_k指出的错误。事实证明这是一个比最初看起来更微妙的问题。

答案 2 :(得分:1)

x = [1,2,3,4,5,1,2,3,4,5,1,2,3,4,5,1,2,3,4,5]
y = [1,2,3]

count = 0
for i in range(len(x)-len(y)):
    if x[i:i+len(y)] == y:
        count += 1
print(count)

答案 3 :(得分:0)

您可以迭代列表并比较子列表:

In [1]: lst = [1,2,3,4,5,1,2,3,4,5,1,2,3,4,5,1,2,3,4,5]
In [2]: sub = [1,2,3]
In [3]: [i for i, _ in enumerate(lst) if lst[i:i+len(sub)] == sub]
Out[3]: [0, 5, 10, 15]

但请注意,在非常大的列表和子列表中,这非常浪费,因为它会创建原始列表的很多片段以与子列表进行比较。在较长的版本中,您可以使用all将列表中的每个相关位置与子列表的相关位置进行比较:

In [5]: [i for i, _ in enumerate(lst) if all(lst[i+k] == e for k, e in enumerate(sub))]
Out[5]: [0, 5, 10, 15]

答案 4 :(得分:0)

这让我觉得每次重复最常见的子序列问题,直到返回的序列为空列表。

我认为在这种情况下,对于高效算法而言,最好的是O(n * m),其中n是大列表中元素的数量,m是小列表中元素的数量。你当然必须有一个额外的步骤,从大序列中删除小序列并重复这个过程。

这是算法:

  1. 查找lcs(bigList,smallList)
  2. 从bigList
  3. 中删除第一个出现的smallList
  4. 重复直到lcs为空列表
  5. 返回迭代次数
  6. 这是我在python中编写的lcs的实现:

    def lcs(first, second):
        results = dict()
        return lcs_mem(first, second, results)
    
    def lcs_mem(first, second, results):
        key = ""
        if first > second:
            key = first + "," + second
        else:
            key = second + "," + first
    
        if len(first) == 0 or len(second) == 0:
            return ''
        elif key in results:
            return results[key]
        elif first[-1] == second[-1]:
            result = lcs(first[:-1], second[:-1]) + first[-1]
            results[key] = result
            return result
        else:
            lcsLeft = lcs(first[:-1], second)
            lcsRight = lcs(first, second[:-1])
    
            if len(lcsLeft) > len(lcsRight):
                return lcsLeft
            else:
                return lcsRight
    
    def main():
        pass
    
    
    if __name__ == '__main__':
        main()
    

    随意将其修改为上述算法。

答案 5 :(得分:0)

可以从复杂性中定义解决方案的效率。在谷歌中搜索有关算法复杂性的更多信息。

在你的情况下,复杂性是2n,其中n是元素的数量。

这是复杂度为n的解决方案,因为它只遍历列表一次,即n次。

def IsSameError(x,y):
    if (len(x) != len(y)):
        return False

    i = 0
    while (i < len(y)):
        if(x[i] != y[i]):
            return False
        i += 1

    return True

x = [1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5]
y = [1, 2, 3]

xLength = len(x)
yLength = len(y)
cnt = 0
answer = []
while (cnt+3 < xLength):
    if(IsSameError([x[cnt], x[cnt+1], x[cnt+2]], y)):
        answer.append(x[cnt])
        answer.append(x[cnt+1])
        answer.append(x[cnt + 2])
        cnt = cnt + 3
    else:
        cnt = cnt + 1


print answer