views:

68

answers:

3

I start with the following list s and bitmask b:

s = ['baa', 'baa', 'black', 'sheep', 'have', 'you', 'any', 'wool']
b = [1, 0, 0, 0, 1, 1, 1, 0] # or any iterable with boolean values

How do I write some function apply_bitmask(s, b) so that it returns

['baa', 'have', 'you', 'any']
+4  A: 
[ item for item, flag in zip( s, b ) if flag == 1 ]
S.Lott
+3  A: 

You can use list comprehensions:

newList = [word for (word, mask) in zip(s,b) if mask]
# Note: Could also use 'if mask == blah', if mask is not a boolean-compatible type.

This first takes the original two lists, and zips them together, so that you get a (temporary - this is still inside the list comp!) list of pairs of words and their masks - something like [('baa',1), ('baa',0),...]. Then only the words that have a mask of 1 (if mask == 1) are added to the newList.

Stephen
Though I'd use `... if mask`, since he asked about true values, not about `1` specifically.
delnan
That is true. I shall add it to the answer. Thanks delnan.
Stephen
+6  A: 

If you can use Python 3.1, itertools.compress does exactly that (the list comprehension is a real close second):

import itertools
filtered = itertools.compress(s, b)

Note that this produces an iterator, not a list. Saves memory, but if you need to iterate it several times or use indices, you can always use list(itertools.compress(s, b)). Still shorter.

delnan
Wow, that's impressive. Cheers for that delnan - never knew about itertools.
Stephen
@Stephen: Itertools is indeed impressive - not only it puts iterators on steroids (as Dive Into Python 3 put it), many of them can be defined in less than 5 lines. Almost feels like Haskell :D
delnan
Can I use that with `2.6.5`?
Kit
@Kit: Only if you copypaste the example definition given in the documentation (or simply adapt it right away, i.e. `result = (i for i, flag in itertools.izip(s, b) if flag)` (zip in Python 3 is izip in Python 2, it's a lazy iterator instead of a list)).
delnan