Finding partial strings in a list of strings - python
Question: I am trying to check if a user is a member of an Active Directory group, and I
have this:

    
    
    ldap.set_option(ldap.OPT_REFERRALS, 0)
    try:
      con = ldap.initialize(LDAP_URL)
      con.simple_bind_s(userid+"@"+ad_settings.AD_DNS_NAME, password)
      ADUser = con.search_ext_s(ad_settings.AD_SEARCH_DN, ldap.SCOPE_SUBTREE, \  
               "sAMAccountName=%s" % userid, ad_settings.AD_SEARCH_FIELDS)[0][1]
    except ldap.LDAPError:
      return None
    

`ADUser` returns a list of strings:

    
    
    {'givenName': ['xxxxx'],
     'mail': ['xxxxx@example.com'],
     'memberOf': ['CN=group1,OU=Projects,OU=Office,OU=company,DC=domain,DC=com',
                  'CN=group2,OU=Projects,OU=Office,OU=company,DC=domain,DC=com',
                  'CN=group3,OU=Projects,OU=Office,OU=company,DC=domain,DC=com',
                  'CN=group4,OU=Projects,OU=Office,OU=company,DC=domain,DC=com'],
     'sAMAccountName': ['myloginid'],
     'sn': ['Xxxxxxxx']}
    

Of course in the real world the group names are verbose and of varied
structure, and users will belong to tens or hundreds of groups.

If I get the list of groups out as `ADUser.get('memberOf')[0]`, what is the
best way to check if any members of a separate list exist in the main list?

For example, the check list would be `['group2', 'group16']` and I want to get
a true/false answer as to whether _any_ of the smaller list exist in the main
list.


Answer: If the format example you give is somewhat reliable, something like:

    
    
    import re
    grps = re.compile(r'CN=(\w+)').findall
    
    def anyof(short_group_list, adu):
      all_groups_of_user = set(g for gs in adu.get('memberOf',()) for g in grps(gs))
      return sorted(all_groups_of_user.intersection(short_group_list))
    

where you pass your list such as `['group2', 'group16']` as the first
argument, your `ADUser` dict as the second argument; this returns an
alphabetically sorted list (possibly empty, meaning "none") of the groups,
among those in `short_group_list`, to which the user belongs.

It's probably not much faster to just a bool, but, if you insist, changing the
second statement of the function to:

    
    
      return any(g for g in short_group_list if g in all_groups_of_user)
    

might possibly save a certain amount of time in the "true" case (since `any`
short-circuits) though I suspect not in the "false" case (where the whole list
must be traversed anyway). If you care about the performance issue, best is to
benchmark both possibilities on data that's realistic for your use case!

If performance isn't yet good enough (and a bool yes/no is sufficient, as you
say), try reversing the looping logic:

    
    
    def anyof_v2(short_group_list, adu):
      gset = set(short_group_list)
      return any(g for gs in adu.get('memberOf',()) for g in grps(gs) if g in gset)
    

`any`'s short-circuit abilities might prove more useful here (at least in the
"true" case, again -- because, again, there's no way to give a "false" result
without examining ALL the possibilities anyway!-).

