Filter down list of elements by comparing their name properties to a list of potential partial matches

Question:

I’m working in python and Revit, and I have a list of detail items with a name parameter. I’d like to filter my list down just the detail items where the name contains a partial match for any string in a list of partial matches. I have a working solution, but my intuition is telling me there ought to be a way to simplify it, since it doesn’t feel very readable to me.

This works:

filtered_detail_items = filter(lambda x: filter_partial_match(
        key = x.LookupParameter('DMER_Panel_Name').AsString(),
        partial_keywords = ['TAP BOX', 'VFD', 'CONTROL PANEL', 'DISC'],
        inclusive = False),
    detail_items)
def filter_partial_match(key, partial_keywords, inclusive = True):

    # Allow user to pass in a single string or a list of strings.
    # If a single string, treat it as a list.
    if type(partial_keywords) is not list: partial_keywords = [ partial_keywords ]

    match_found = False
    if any(x in key for x in partial_keywords):
        match_found = True

    if inclusive:
        return match_found
    else:
        return not match_found

This doesn’t:

filtered_detail_items = [(lambda x: (if any(y in x.LookParameter('DMER_Panel_Name').AsString() for y in ['TAP BOX', 'VFD', 'CONTROL PANEL', 'DISC']): x)) for x in detail_items ]
Asked By: mybluesock

||

Answers:

You don’t need lambda in a list comprehension. Call the function directly in the if condition of the generator.

filtered_detail_items = [
    x for x in detail_items 
    if filter_partial_match(
        key = x.LookupParameter('DMER_Panel_Name').AsString(),
        partial_keywords = ['TAP BOX', 'VFD', 'CONTROL PANEL', 'DISC'],
        inclusive = False)
]

If you want to do this without defining the filter_partial_match() function, you’d have to extract the code from the body and hard-code the parameters.

filtered_detail_items = [
    x for x in detail_items
    if not any(y in x.LookupParameter('DMER_Panel_Name').AsString() for y in ['TAP BOX', 'VFD', 'CONTROL PANEL', 'DISC'])
]
Answered By: Barmar

Per comments from Jeremy and Barmar, here is the final solution I used:

#filter out partial_matches that we don't want in the names.
partial_matches = ['TAP BOX', 'VFD', 'CONTROL PANEL', 'DISC']

first_item = riser_detail_items.FirstElement()
if first_item:
    name_definition = first_item.LookupParameter('DMER_Panel_Name').Definition

riser_detail_items = [
    x for x in riser_detail_items
    if not any(
        partial_match in x.get_Parameter(name_definition).AsString()
        for partial_match in partial_matches
    )
]
Answered By: mybluesock
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.