Find First Sequence Item That Matches a Criterion

Find first sequence item that matches a criterion

If you don't have any other indexes or sorted information for your objects, then you will have to iterate until such an object is found:

next(obj for obj in objs if obj.val == 5)

This is however faster than a complete list comprehension. Compare these two:

[i for i in xrange(100000) if i == 1000][0]

next(i for i in xrange(100000) if i == 1000)

The first one needs 5.75ms, the second one 58.3µs (100 times faster because the loop 100 times shorter).

Get the first item from an iterable that matches a condition

Python 2.6+ and Python 3:

If you want StopIteration to be raised if no matching element is found:

next(x for x in the_iterable if x > 3)

If you want default_value (e.g. None) to be returned instead:

next((x for x in the_iterable if x > 3), default_value)

Note that you need an extra pair of parentheses around the generator expression in this case − they are needed whenever the generator expression isn't the only argument.

I see most answers resolutely ignore the next built-in and so I assume that for some mysterious reason they're 100% focused on versions 2.5 and older -- without mentioning the Python-version issue (but then I don't see that mention in the answers that do mention the next built-in, which is why I thought it necessary to provide an answer myself -- at least the "correct version" issue gets on record this way;-).

Python <= 2.5

The .next() method of iterators immediately raises StopIteration if the iterator immediately finishes -- i.e., for your use case, if no item in the iterable satisfies the condition. If you don't care (i.e., you know there must be at least one satisfactory item) then just use .next() (best on a genexp, line for the next built-in in Python 2.6 and better).

If you do care, wrapping things in a function as you had first indicated in your Q seems best, and while the function implementation you proposed is just fine, you could alternatively use itertools, a for...: break loop, or a genexp, or a try/except StopIteration as the function's body, as various answers suggested. There's not much added value in any of these alternatives so I'd go for the starkly-simple version you first proposed.

Return the first item in a list matching a condition

next(x for x in lst if matchCondition(x)) 

should work, but it will raise StopIteration if none of the elements in the list match. You can suppress that by supplying a second argument to next:

next((x for x in lst if matchCondition(x)), None)

which will return None if nothing matches.

Demo:

>>> next(x for x in range(10) if x == 7)  #This is a silly way to write 7 ...
7
>>> next(x for x in range(10) if x == 11)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
>>> next((x for x in range(10) if x == 7), None)
7
>>> print next((x for x in range(10) if x == 11), None)
None

Finally, just for completeness, if you want all the items that match in the list, that is what the builtin filter function is for:

all_matching = filter(matchCondition,lst)

In python2.x, this returns a list, but in python3.x, it returns an iterable object.

How to find first element in a sequence that matches a predicate in Python?

You can combine ifilter and islice to get just the first matching element.

>>> list(itertools.islice(itertools.ifilter(lambda n: n % 2 == 0, lst), 1))
[8]

However, I wouldn't consider this anyhow more readable or nicer than the original code you posted. Wrapped in a function it will be much nicer though. And since next only returns one element there is no need for islice anymore:

def find(pred, iterable):
return next(itertools.ifilter(pred, iterable), None)

It returns None if no element was found.

However, you still have the rather slow call of the predicate function every loop. Please consider using a list comprehension or generator expression instead:

>>> next((x for x in lst if x % 2 == 0), None)
8

Fetch first element of stream matching the criteria

This might be what you are looking for:

yourStream
.filter(/* your criteria */)
.findFirst()
.get();

And better, if there's a possibility of matching no element, in which case get() will throw a NPE. So use:

yourStream
.filter(/* your criteria */)
.findFirst()
.orElse(null); /* You could also create a default object here */
An example:
public static void main(String[] args) {
class Stop {
private final String stationName;
private final int passengerCount;

Stop(final String stationName, final int passengerCount) {
this.stationName = stationName;
this.passengerCount = passengerCount;
}
}

List<Stop> stops = new LinkedList<>();

stops.add(new Stop("Station1", 250));
stops.add(new Stop("Station2", 275));
stops.add(new Stop("Station3", 390));
stops.add(new Stop("Station2", 210));
stops.add(new Stop("Station1", 190));

Stop firstStopAtStation1 = stops.stream()
.filter(e -> e.stationName.equals("Station1"))
.findFirst()
.orElse(null);

System.out.printf("At the first stop at Station1 there were %d passengers in the train.", firstStopAtStation1.passengerCount);
}

Output is:

At the first stop at Station1 there were 250 passengers in the train.

Using map reduce etc, how would you find the first item matching a certain criteria in a nested array, and stop once found?

The easiest (though slightly ugly) solution would be to assign the matching item to an outer variable when found:

let foundNested;
data.some(subarr => (
subarr.some((item) => {
if (myPredicate(item)) {
foundNested = item;
return true;
}
});
});

You might use .reduce to avoid assigning to an outer variable:

const myPredicate = ({ val }) => val === 5;const data = [  {arr: [{val:6,name:'aaa'},{val:4,name:'bbb'},{val:8,name:'ccc'}]},  {arr: [{val:3,name:'mmm'},{val:5,name:'nnn'},{val:9,name:'ppp'},{val:5,name:'ooo'}]}];
const found = data.reduce((a, { arr }) => ( a || arr.find(myPredicate)), null);console.log(found);

Concise Way of Get Matching Element in List

You're pretty much there. If you use a generator- rather than list-comprehension, you can then pass it to next, which takes the first item.

try:
x = next(dict_elem for dict_elem in list_above if dict_elem['name'] == reded)
except StopIteration:
print "No match found"

Or

x = next((dict_elem for dict_elem in list_above if dict_elem['name'] == reded), None)
if not x:
print "No match found"

Concise Way of Get Matching Element in List

You're pretty much there. If you use a generator- rather than list-comprehension, you can then pass it to next, which takes the first item.

try:
x = next(dict_elem for dict_elem in list_above if dict_elem['name'] == reded)
except StopIteration:
print "No match found"

Or

x = next((dict_elem for dict_elem in list_above if dict_elem['name'] == reded), None)
if not x:
print "No match found"


Related Topics



Leave a reply



Submit