[英]Check that python list follows a specific repeating pattern
我有一個 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']
任何偏離l
中a,b
重復模式的東西都必須被認為是損壞的。 即使列表的長度不均勻,它也會被破壞。 所以這一定是一個非常嚴格的測試。 但本質上,如果列表l
的長度為N
,則意味着(a,b)
必須重復N/2
次。 符號a
和b
是唯一會出現在這些列表中的東西,因此不需要檢查它,因為在這個應用程序中它是不可想象的,其他任何東西都可以看到。
我應該說他們都應該有第一個模式。 我正在尋找一種有效的方法,一種測試,它可以確定每個列表實際上確實具有這種重復模式。 如果不拋出錯誤或其他東西,例如
assert my_fancy_test(l), 'the list does not follow the correct pattern'
我想我正在尋找子序列匹配,但我的谷歌搜索不足。
感謝大家的出色解決方案。 我不知道你能做到這些的一半。 好東西。 我在最后添加了一個簡短的性能概述供您閱讀。
您的列表中是否還有其他符號,並且列表的長度可以被 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]
如果它們都通過了,那一定意味着您只有兩個符號,而隨后的兩個符號永遠不會相同
測試列表: 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
西爾弗斯的回答:
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
蒂圖斯班的回答:
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
基於列表乘法的簡單測試function:
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
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
一種方法可能是首先配對:
>>> 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,大寫名稱只能用於常量。
您可以使用:
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))
output:
---------------------------------------------------------------------------
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:
另一種方法是加入列表並使用正則表達式進行模式匹配:
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']))
Output:
False
True
這種方法也可以用來有效地匹配一些更復雜的模式,或者在匹配模式的同時提取信息。
當且僅當滿足以下四個要求時,列表才是正確的:
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
計算,並且如果發現不正確的條目,則不會檢查列表的其余部分(查看all
內置方法的文檔)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.