amateur3057 amateur3057 - 2 months ago 7
Python Question

Find generic sub-lists within a list

Just learning Python as my first coding language. Given a list with many possible sub-lists which have a variable number of elements, is there a way of using regex (or something similar) to identify which lists contain sub-lists with 1) the number of elements specified and 2) a given type of content in a certain order (including other sub-lists)? For example (in pseudocode):

list1 = [1, 4, 7, ["a", 5, "b"], 2, 4,7,"k",9]
list2 = [1, 4, 7, ["a", "h", "b"], 2]
list3 = [1, 4, 7, ["a", ["a", 6, "b"], "b"], 5, 3]

list4 = [1, 4, 7, ["a", "b"], 3, 4]
list5 = [1, 4, 7, ["a", 5, "b", 7], 3, 4]

if ["a", ., "b"] in listx: # where "." stands for anything, even sub-lists
print("yes")
else:
print("no")


list1, list2, and list3 should print "yes", but list4 and list5 should print "no".

As a bonus, is there a way to return 1) the number of times that the specified generic sub-list is found and 2) where? For example, have list3 return "There are 2 ["a", ., "b"] sub-lists, which are list3[3] and list3[3][1]"

I know I could convert the whole thing to a string and parse it, but this doesn't seem like a very elegant or efficient solution. Thank you!

Answer

I agree that converting to string doesn't make any sense here, but regular expressions explicitly search strings so you're not looking for that either. You're looking for a recursive solution that tests for your rules, which are (essentially)

somelist IS or CONTAINS a list that begins with the string "a", ends with the string "b", and has three or more elements.

Codify that into:

def flat_pass(lst):
    return len(lst) >= 3 and lst[0] == 'a' and lst[-1] == 'b'

Now you just have to recurse (to catch the "CONTAINS" part of the above rules)

def recurse_pass(lst):
    if len(lst) >= 3 and lst[0] == 'a' and lst[-1] == 'b':
        # base case
        return True
    # otherwise, flow continues...
    for el in lst:
        if isinstance(el, list):
            # recursive case
            if recurse_pass(el):
                return True
    return False