我想计算一个大清单包含特定顺序元素的次数。例如,如果我有元素[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添加到计数器并继续寻找。我相信这个解决方案效率不高并且看起来不太好,是否会有更好的解决方案?
答案 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是小列表中元素的数量。你当然必须有一个额外的步骤,从大序列中删除小序列并重复这个过程。
这是算法:
这是我在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