我有一个仅包含两个符号的python列表,可以说它们是a
和b
,列表看起来像这样:
l = ['a','b','a','b','a','b','a','b','a','b','a','b','a','b','a','b']
现在在我的应用程序中,我有成千上万个这样的列表,它们的长度各不相同(通常为几百个长)。但是它们的共同点在于它们具有重复模式(a,b)
。例如,此列表已损坏:
l_broken = ['a','b','b','a','a','b','a','b','a','a','a','b','a','b','b','a']
任何与a,b
中的l
重复模式不同的内容都应视为已损坏。即使列表长度不均,它也会被破坏。因此,这必须是一个非常严格的测试。但实际上,如果列表l
的长度为N
,则意味着(a,b)
必须重复自身N/2
次。符号a
和b
是将仅出现在这些列表中的内容,因此不需要进行检查,因为在此应用程序中它是不可想象的,因此可以看到其他任何内容。
我应该说,他们所有人都应该具有 first 模式。我正在寻找一种有效的方法,即测试,可以确定每个列表确实具有这种重复模式。如果没有抛出错误或类似的东西
assert my_fancy_test(l), 'the list does not follow the correct pattern'
我想我正在寻找子序列匹配,但是我的Google搜索不足。
感谢大家提供出色的解决方案。我不知道你能做到其中一半。好东西。最后,我添加了简短的性能概述,供您仔细阅读。
答案 0 :(得分:3)
列表中是否还有其他符号,并且列表的长度可以除以2:
assert len(l) == l.count('a') + l.count('b') and len(L) % 2 == 0
并且没有重复的符号:
j = ''.join(l)
assert 'aa' not in j and 'bb' not in j
列表中的第一项是'a'
assert 'a' is L[0]
如果它们全部通过,那就意味着您只有两个符号,并且两个后续符号永远不会相同
答案 1 :(得分:3)
测试列表:l = ['a','b']*100000
RomanPerekhrest的解决方案:
CPU times: user 636 µs, sys: 0 ns, total: 636 µs
Wall time: 639 µs
GZ0的答案:
CPU times: user 14.6 ms, sys: 78 µs, total: 14.7 ms
Wall time: 13.9 ms
Silveris'答案:
CPU times: user 95.2 ms, sys: 3.95 ms, total: 99.1 ms
Wall time: 98 ms
h4z3的答案:
CPU times: user 39.9 ms, sys: 0 ns, total: 39.9 ms
Wall time: 38.6 ms
tituszban的答案:
CPU times: user 2.71 ms, sys: 46 µs, total: 2.76 ms
Wall time: 2.76 ms
ruso_ro1答案:
CPU times: user 32.4 ms, sys: 3.35 ms, total: 35.8 ms
Wall time: 34.7 ms
CPU times: user 11.7 ms, sys: 0 ns, total: 11.7 ms
Wall time: 12.1 ms
答案 2 :(得分:2)
基于列表乘法的简单测试功能:
def test_repeating_pattern(lst, pat):
pat_len = len(pat)
assert len(lst) % pat_len == 0, 'mismatched length of list'
assert list(pat) * (len(lst) // pat_len) == lst, 'the list does not follow the correct pattern'
print(lst, 'is valid')
L = ['a','b','a','b','a','b','a','b','a','b','a','b','a','b','a','b']
L_broken = ['a','b','b','a','a','b','a','b','a','a','a','b','a','b','b','a']
测试:
test_repeating_pattern(L, ('a', 'b'))
['a', 'b', 'a', 'b', 'a', 'b', 'a', 'b', 'a', 'b', 'a', 'b', 'a', 'b', 'a', 'b'] is valid
test_repeating_pattern(L_broken, ('a', 'b'))
AssertionError: the list does not follow the correct pattern
答案 3 :(得分:1)
def my_fancy_test(my_list):
pattern = ['a', 'b']
if not len(my_list) % len(pattern) == 0:
return False
for i in range(0, len(my_list)):
if not my_list[i] == pattern[i % len(pattern)]:
return False
return True
模式可以是任何长度的任何列表(通用解)。
仅检查完整模式(例如a,b,a会失败),并且模式必须从头开始(例如b,a,b也将失败)。
L = ['a','b','a','b','a','b','a','b','a','b','a','b','a','b','a','b']
assert my_fancy_test(L) #passes
L2 = ['a','b','a','b','a','b','a','b','a','b','a','b','a','b','a','c']
assert my_fancy_test(L2) #fails
答案 4 :(得分:1)
一种方法可能是先配对:
>>> l = ['a','b','a','b','a','b','a','b','a','b','a','b','a','b','a','b']
>>> pairs = [[l[i], l[i + 1]] for i in range(0, len(l) - 1, 2)]
>>> pairs
[['a', 'b'], ['a', 'b'], ['a', 'b'], ['a', 'b'], ['a', 'b'], ['a', 'b'], ['a', 'b'], ['a', 'b']]
然后计算对列表中['a', 'b']
的出现,并将其与列表大小的一半进行比较:
>>> pairs.count(['a', 'b']) == len(l) / 2
True
它看起来像:
def my_fancy_test(l):
pairs = [[l[i], l[i + 1]] for i in range(0, len(l) - 1, 2)]
return pairs.count(['a', 'b']) == len(l) / 2
PS:请注意,根据PEP8,大写名称只能用于常量。
答案 5 :(得分:0)
您可以使用:
pattern = ['a', 'b']
p_len = len(pattern)
assert all(pattern == L[i: i + p_len] for i in range(0, len(L), p_len))
您要逐个抽取图案大小的块,然后针对该图案进行测试
例如:
pattern = ['a', 'b']
p_len = len(pattern)
l_broken = ['a','b','b','a','a','b','a','b','a','a','a','b','a','b','b','a']
all(pattern == l_broken[i: i+p_len] for i in range(0, len(l_broken), p_len))
输出:
---------------------------------------------------------------------------
AssertionError Traceback (most recent call last)
<ipython-input-160-edf435d855b9> in <module>
1 p_len = len(pattern)
2 l_broken = ['a','b','b','a','a','b','a','b','a','a','a','b','a','b','b','a']
----> 3 assert all(pattern == l_broken[i: i+p_len] for i in range(0, len(l_broken), p_len))
AssertionError:
答案 6 :(得分:0)
另一种方法是加入列表并使用正则表达式进行模式匹配:
import re
def is_broken(input_list, pattern = re.compile("(?:ab)*")):
return pattern.fullmatch(''.join(input_list)) is None
print(is_broken(['a','b','a','b','a','b','a','b','a','b','a','b','a','b','a','b']))
print(is_broken(['a','b','b','a','a','b','a','b','a','a','a','b','a','b','b','a']))
输出:
False
True
这种方法还可以用于高效地匹配一些更复杂的模式,或者在匹配模式时提取信息。
答案 7 :(得分:0)
仅且满足以下四个要求的列表是正确的:
b
a
b
def is_correct_entry(idx, v):
if idx % 2 == 0:
return v == 'a'
else:
return v == 'b'
def my_fancy_test(l):
return l and l[-1] == 'b' and all(is_correct_entry(idx, v) for idx, v in enumerate(l))
此代码可能具有速度优势,因为它不会创建新列表,避免了昂贵的len
计算,并且如果发现不正确的条目也不会检查列表的其余部分(请检查documentation all
内置方法)。