[NCLUG] help w/ python list comprehension

Mike Cullerton michaelc at cullerton.com
Tue Aug 27 20:46:46 MDT 2013


Using sets is the way I decided to go. 

I'm adding a tag filter to an existing rss feed product, and really want to have both 'all' and 'or' versions. 

Cool stuff in here, Sean.

Mike

On Aug 27, 2013, at 8:29 PM, Sean Reifschneider <jafo at tummy.com> wrote:

> On 08/21/2013 09:54 AM, Mike Cullerton wrote:
>>    for item in items:
>>        missing = False
>>        for tag in tags:
>>            # do we have a tag (ignore tag == '')
>>            # can we find it in item.tags
>>            if tag and not tag.lower() in [tag.lower() for tag in item.tags]:
>>                missing = True
>>                break
>>        if not missing: items_by_tag.append(item)
>>    return items_by_tag
> 
> One thing I'd recommend against is the duplicate use of tag in the
> comprehension:
> 
>            if tag and not tag.lower() in [tag.lower() for tag in item.tags]:
> 
> Instead, I tend to use "x" for things that are temporary in a
> comprehension:
> 
>            if tag and not tag.lower() in [x.lower() for x in item.tags]:
> 
> That reduces any confusion about the multiple uses of tag.
> 
> You're also computing the item.tags multiple times, so it might be more
> obvious to make it:
> 
>    for item in items:
>        item_tags_lower = [x.lower() for x in item.tags]
>        missing = False
>        for tag in tags:
>            # do we have a tag (ignore tag == '')
>            # can we find it in item.tags
>            if tag and not tag.lower() in item_tags_lower:
>                missing = True
>                break
>        if not missing: items_by_tag.append(item)
>    return items_by_tag
> 
> One place you can use a list comprehension here is to get rid of the "if
> tag":
> 
>    for item in items:
>        item_tags_lower = [x.lower() for x in item.tags]
>        missing = False
>        for tag in [x for x in tags if x]:
>            if not tag.lower() in item_tags_lower:
>                missing = True
>                break
>        if not missing: items_by_tag.append(item)
>    return items_by_tag
> 
> But you're also re-computing the tag.lower() as well, so:
> 
>    tags_lower = [x.lower() for x in tags if x]:
>    for item in items:
>        item_tags_lower = [x.lower() for x in item.tags]
>        missing = False
>        for tag in tags_lower:
>            if not tag in item_tags_lower:
>                missing = True
>                break
>        if not missing: items_by_tag.append(item)
>    return items_by_tag
> 
> But, I believe what you're trying to do here is to return a list of items
> that have a tag in the list of tags, right?  This is something that sets
> can help us with, because we can use logic operators on sets:
> 
>>>> set([1,2,3]) & set([4,5,6])
>    set([])
>>>> set([1,2,3]) & set([3,4,5])
>    set([3])
> 
> So:
> 
>    tags_set = set([x.lower() for x in tags if x])
>    return [x for x in items if
>            set([x.lower() for x in item.tags]) & tags_set]
> 
> That has the benefit of not turning an iterator into a static list, if you
> are dealing with a huge list of items, say from a database...
> 
> Is that, as Stephen says, less clear?  Well, I'd say that the last example
> above is much more clear than the original code.  But it could probably be
> made more clear with:
> 
>    tags_set = set([x.lower() for x in tags if x])
> 
>    def any_matching_tags(search):
>        return set([x.lower() for x in item.tags]) & tags_set
> 
>    return [x for x in items if any_matching_tags(x)]
> 
> Sean
> _______________________________________________
> NCLUG mailing list       NCLUG at lists.nclug.org
> 
> To unsubscribe, subscribe, or modify
> your settings, go to:
> http://lists.nclug.org/mailman/listinfo/nclug



More information about the NCLUG mailing list