簡體   English   中英

檢查 python 列表是否遵循特定的重復模式

[英]Check that python list follows a specific repeating pattern

我有一個 python 列表,其中僅包含兩個符號,假設它們是ab ,列表如下所示:

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

任何偏離la,b重復模式的東西都必須被認為是損壞的。 即使列表的長度不均勻,它也會被破壞。 所以這一定是一個非常嚴格的測試。 但本質上,如果列表l的長度為N ,則意味着(a,b)必須重復N/2次。 符號ab是唯一會出現在這些列表中的東西,因此不需要檢查它,因為在這個應用程序中它是不可想象的,其他任何東西都可以看到。

我應該說他們都應該有第一個模式。 我正在尋找一種有效的方法,一種測試,它可以確定每個列表實際上確實具有這種重復模式。 如果不拋出錯誤或其他東西,例如

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM