working - wordpress top level menu item not clickable




Stopping list selection? (6)

Imagine that I have an order list of tuples:

s = [(0,-1), (1,0), (2,-1), (3,0), (4,0), (5,-1), (6,0), (7,-1)]

Given a parameter X, I want to select all the tuples that have a first element equal or greater than X up to but not including the first tuple that has -1 as the second element.

For example, if X = 3, I want to select the list [(3,0), (4,0)]

One idea I had is: Get the cut-off key with

E = min (x [0] for x in s if (x [0] >= X) and (x [1] == -1) )

Then select elements with keys between the X and E:

R = [x for x in s if X <= x [0] < E]

That gives me what I want in R, but it seems really inefficient, involving two table scans. I could do it in a for loop, discarding tuples with keys too small, and break when I hit the first blocking tuple. But for runs like a dog compared to list selection.

Is there a super-efficient, python-esque (2.7) way of doing this?


itertools.takewhile works well if you want a new list. To modify the original list in-place you could do:

>>> L = ['pin 2.3','vlo 5.4', '2 packages installed', 'bla-bla']
>>> for i, v in enumerate(L):
...     if "packages installed" in v:
...         del L[i:]
...         break
... 
>>> L
['pin 2.3', 'vlo 5.4']

Because the syntax of takewhile() and dropwhile() is not the clearest, here are the actual examples of your question:

>>> [i for i in itertools.takewhile(lambda x: x*x<30, range(10))]
[0, 1, 2, 3, 4, 5]
>>> [i for i in itertools.dropwhile(lambda x: x*x<30, range(10))]
[6, 7, 8, 9] 

Know that the author of itertools has questioned whether to deprecate these functions.


Something simple:

li1 = ['pin 2.3','vlo 5.4', 'lu 1.3', '3 packages installed', '', 'bla']

out1 = []
for x in li1:
    if "packages installed" in x:
        break
    out1.append(x)

print(out1)
# ['pin 2.3', 'vlo 5.4', 'lu 1.3']

Edit: It seems like I'm a little bit late.


You can simply filter the tuples from the list as a generator expression and then you can stop taking the values from the generator expression when you get the first tuple whose second element is -1, like this

>>> s = [(0,-1), (1,0), (2,-1), (3,0), (4,0), (5,-1), (6,0), (7,-1)]
>>> from itertools import takewhile
>>> X = 3
>>> list(takewhile(lambda x: x[1] != -1, (item for item in s if item[0] >= X)))
[(3, 0), (4, 0)]

Here, the generator expression, (item for item in s if item[0] >= X) will give values one-by-one, on demand, (they are not generated all at once, so we save memory here) which are greater than or equal to X.

Then, we take values from that generator expression, only till we find a tuple whose second element is not equal to -1, with itertools.takewhile.


Using while in list comprehension or generator expressions

The various functions in itertools (takewhile() comes to mind) can help.


python: filter a list of strings based on a string name

You can use itertools.takewhile, which takes items from the list until the given condition is not passed:

from itertools import takewhile

l12 = ['pin 2.3','vlo 5.4', '2 packages installed', 'bla', 'bla']
li1 = ['pin 2.3','vlo 5.4', 'lu 1.3', '3 packages installed', '', 'bla']



r12 = takewhile(lambda x: "packages installed" not in x, l12)
ri1 = takewhile(lambda x: "packages installed" not in x, li1)
print(list(r12))
# ['pin 2.3', 'vlo 5.4']

print(list(ri1))
# ['pin 2.3', 'vlo 5.4', 'lu 1.3']