Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Stopping list selection? [duplicate]

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?

like image 604
Terrible Tadpole Avatar asked Jun 23 '15 12:06

Terrible Tadpole


People also ask

How do you avoid duplication in a list?

If you don't want duplicates, use a Set instead of a List . To convert a List to a Set you can use the following code: // list is some List of Strings Set<String> s = new HashSet<String>(list); If really necessary you can use the same construction to convert a Set back into a List .

How do I remove duplicates from selectively in Excel?

To filter for unique values, click Data > Sort & Filter > Advanced. To remove duplicate values, click Data > Data Tools > Remove Duplicates. To highlight unique or duplicate values, use the Conditional Formatting command in the Style group on the Home tab.


2 Answers

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.

like image 137
thefourtheye Avatar answered Sep 25 '22 06:09

thefourtheye


Here's a slightly hacky to implement takewhile as part of a generator expression:

def stop(): raise StopIteration

result = (
    stop() if item[1] == -1 else
    item
    for item in s
    if item[0] >= X
)

Or with different phrasing:

def until(cond):
    if cond: raise StopIteration
    return True

result = (
    item for item in s
    if item[0] >= X
    and until(item[1] == -1)
)
like image 39
Eric Avatar answered Sep 22 '22 06:09

Eric