Skip to content

Commit c767441

Browse files
committed
Add find_or_last method
1 parent 59cb6f5 commit c767441

File tree

1 file changed

+27
-0
lines changed

1 file changed

+27
-0
lines changed

src/lib.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#![warn(missing_docs)]
22
#![crate_name="itertools"]
33
#![cfg_attr(not(feature = "use_std"), no_std)]
4+
#![feature(control_flow_enum)]
45

56
//! Extra iterator adaptors, functions and macros.
67
//!
@@ -75,6 +76,7 @@ use std::fmt::Write;
7576
type VecIntoIter<T> = alloc::vec::IntoIter<T>;
7677
#[cfg(feature = "use_alloc")]
7778
use std::iter::FromIterator;
79+
use std::ops::ControlFlow;
7880

7981
#[macro_use]
8082
mod impl_macros;
@@ -1730,7 +1732,32 @@ pub trait Itertools : Iterator {
17301732
}
17311733
None
17321734
}
1735+
/// Find the value of the first element satisfying a predicate or return the last element, if any.
1736+
///
1737+
/// The iterator is not advanced past the first element found.
1738+
///
1739+
/// ```
1740+
/// use itertools::Itertools;
1741+
///
1742+
/// let numbers = [1, 2, 3, 4];
1743+
/// assert_eq!(numbers.iter().find_or_last(|x| x > 5), Some(4));
1744+
/// ```
1745+
fn find_or_last<P>(mut self, predicate: P) -> Option<Self::Item>
1746+
where Self: Sized,
1747+
P: FnMut(&Self::Item) -> bool,
1748+
{
1749+
#[inline]
1750+
fn check<T>(mut predicate: impl FnMut(&T) -> bool) -> impl FnMut(Option<T>, T) -> ControlFlow<T, Option<T>> {
1751+
move |_, x| {
1752+
if predicate(&x) { ControlFlow::Break(x) } else { ControlFlow::Continue(Some(x)) }
1753+
}
1754+
}
17331755

1756+
match self.try_fold(None, check(predicate)) {
1757+
ControlFlow::Continue(x) => x,
1758+
ControlFlow::Break(x) => Some(x),
1759+
}
1760+
}
17341761
/// Returns `true` if the given item is present in this iterator.
17351762
///
17361763
/// This method is short-circuiting. If the given item is present in this

0 commit comments

Comments
 (0)