Search code examples
pythonstructural-pattern-matching

Structural pattern matching python - match at any position in sequence


I have a list of objects, and want to check if part of the list matches a specific pattern.

Consider the following lists:

l1 = ["foo", "bar"]
l2 = [{1, 2},"foo", "bar"]
l3 = ["foo", "bar", 5]
l4 = [{1,2},"foo", "bar", 5, 6]

How would I match the sequence ["foo", "bar"] in all the different cases?

My naive idea is:

match l4:
    case [*_, "foo", "bar", *_]:
        print("matched!")

Unfortunately this is a SyntaxError: multiple starred names in sequence pattern. The issue is, that I don't know how many elements are leading and trailing the pattern.

Edit: I think I need to clarify: "foo", "bar" is just a stand-in for a much more complex pattern. (I am working with an AST object)


Solution

  • def struct_match(lst_target, lst_pattern):
        for i in range(len(lst_target)-(len(lst_pattern)-1)):
            if lst_target[i:i+len(lst_pattern)] == lst_pattern:
                print('matched!')
                break
    
    l1 = ["foo", "bar"]
    l2 = [{1, 2},"foo", "bar"]
    l3 = ["foo", "bar", 5]
    l4 = [{1,2},"foo", "bar", 5, 6]
    l5 = [{1,2},"foo", "baz", "bar", 5, 6]
    
    patt = ["foo", "bar"]
    
    struct_match(l1, patt)
    struct_match(l2, patt)
    struct_match(l3, patt)
    struct_match(l4, patt)
    struct_match(l5, patt)
    
    
    # outputs
    
    matched!
    matched!
    matched!
    matched!
    

    PS: I just found a beautiful recursive solution here (recursion is always beautiful... if your list is not too long)