[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