Search code examples
pythonlist-comprehensionnested-loops

How to make nested for loop more Pythonic


I have to create a list of blocked users per key. Each user has multiple attributes and if any of these attributes are in keys, the user is blocked.

I wrote the following nested for-loop and it works for me, but I want to write it in a more pythonic way with fewer lines and more readable fashion. How can I do that?

for key in keys:
    key.blocked_users = []

for user in get_users():
    for attribute in user.attributes:
        for key in keys:
            if attribute.name == key.name:
                key.blocked_users.append(user)

Solution

  • Aside from making it shorter, you could try to reduce the operations to functions that are optimized in Python. It may not be shorter but it could be faster then - and what's more pythonic than speed?. :)

    For example you iterate over the keys for each attribute of each user. That just sreams to be optimized "away". For example you could collect the key-names in a dictionary (for the lookup) and a set (for the intersection with attribute names) once:

    for key in keys:
        key.blocked_users = []
    
    keyname_map = {key.name: key.blocked_users for key in keys}  # map the key name to blocked_user list
    keynames = set(keyname_map)
    

    The set(keyname_map) is a very efficient operation so it doesn't matter much that you keep two collections around.

    And then use set.intersection to get the keynames that match an attribute name:

    for user in get_users():
        for key in keynames.intersection({attribute.name for attribute in user.attributes}):
            keyname_map[key].append(user)
    

    set.intersection is pretty fast too.

    However, this approach requires that your attribute.names and key.names are hashable.