John Krukoff wrote: > > [EMAIL PROTECTED] wrote: > > Hi, > > > > I'm playing around with list comprehension, and I'm trying to find the > > most aesthetic way to do the following: > > > > I have two lists: > > > > noShowList = ['one', 'two', 'three'] > > > > myList = ['item one', 'item four', 'three item'] > > > > I want to show all the items from 'myList' that do not contain any of > > the strings in 'noShowList'. > > > > i.e. 'item four' > > > > I can do it like this: > > > > def inItem(noShowList, listitem): > > return [x for x in noShowList if x in listitem] > > > > print [x for x in myList if not inItem(noShowList, x)] > > > > and I can do it (horribly) with: > > > > print [x for x in myList if not (lambda y, z:[i for i in y if i in z]) > > (noShowList, x)] > > > > I can also print out the items that DO contain the 'noShowList' > > strings with: > > > > print [x for x in myList for y in noShowList if y in x] > > > > but I can't get the 'not' bit to work in the above line. > > > > Any ideas? > > Thanks! > > > > -- > > http://mail.python.org/mailman/listinfo/python-list > > So, conceptually speaking, you're dealing with two loops here, one over > the items to filter, and one over the items to check for substring > matches. If you want to do that with list comprehensions, I'd make it > obvious that there's two of them: > > >>> [ listItem for listItem in myList if not [ noShow for noShow in > noShowList if noShow in listItem ] ] > ['item four'] > > This is a pretty good place for the functional programming tools though, > specifically "filter", > http://docs.python.org/tut/node7.html#SECTION007130000000000000000 > , which gives a solution that looks like this: > > >>> filter( lambda listItem : not [ noShow for noShow in noShowList if > noShow in listItem ], myList ) > ['item four'] > > or using purely functional tools, like this: > > >>> filter( lambda listItem : not sum( map( lambda noShow: noShow in > listItem, noShowList ) ), myList ) > ['item four'] > > All these solutions have the problem that they're still less efficient > than the unwrapped for loop, like so: > > >>> aFiltered = [] > >>> for listItem in myList: > ... for noShow in noShowList: > ... if noShow in listItem: > ... break > ... else: > ... aFiltered.append( listItem ) > ... > >>> aFiltered > ['item four'] > > This is due to the list comprehensions testing all the possiblities, > instead of giving up on the first one found. You can jam that early break > into the functional approach using itertools, but it starts to look really > ugly on one line (requires 2.5 for if expression): > > >>> list( itertools.ifilter( lambda listItem : True if len( list( > itertools.takewhile( lambda test : not test, itertools.imap( lambda > noShow: noShow in listItem, noShowList ) ) ) ) == len( noShowList) else > False, myList ) ) > ['item four'] > > Which can be made to look much better by breaking the 'noShow in listItem' > test out into a separate function, and does have the advantage that by > using itertools.ifilter this is a lazy approach. There's got to be a > better way to do the test to see if takewhile bailed early than using len, > though. > > --------- > John Krukoff > [EMAIL PROTECTED]
Ah, yeah, any was the function I needed to simplify things and do the early break. I really need to upgrade to 2.5. >>> list( itertools.ifilter( lambda listItem : not any( itertools.imap( lambda noShow: noShow in listItem, noShowList ) ), myList ) ) ['item four'] Thanks Jason! --------- John Krukoff [EMAIL PROTECTED] -- http://mail.python.org/mailman/listinfo/python-list