Skip to content

Commit 271a341

Browse files
Merge #535
535: Add `find_or_last` method to `Itertools` trait r=jswrenn a=mankinskin [Playground](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=6abc43c9037445f88fb0a86991da01f2) ```rust fn find_or_last(mut self, predicate: impl FnMut(&Self::Item) -> bool) -> Option<Self::Item> ``` - returns `None` if iterator is empty - returns `Some(element)` when element matches the predicate - returns `Some(last_element)` when no element matches the predicate [Related discussion on the rust user forum](https://users.rust-lang.org/t/find-or-return-last-element-of-iterator/58171) Co-authored-by: Linus Behrbohm <[email protected]>
2 parents b87fc76 + 086b7d2 commit 271a341

File tree

1 file changed

+43
-1
lines changed

1 file changed

+43
-1
lines changed

src/lib.rs

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1756,7 +1756,49 @@ pub trait Itertools : Iterator {
17561756
}
17571757
None
17581758
}
1759-
1759+
/// Find the value of the first element satisfying a predicate or return the last element, if any.
1760+
///
1761+
/// The iterator is not advanced past the first element found.
1762+
///
1763+
/// ```
1764+
/// use itertools::Itertools;
1765+
///
1766+
/// let numbers = [1, 2, 3, 4];
1767+
/// assert_eq!(numbers.iter().find_or_last(|&&x| x > 5), Some(&4));
1768+
/// assert_eq!(numbers.iter().find_or_last(|&&x| x > 2), Some(&3));
1769+
/// assert_eq!(std::iter::empty::<i32>().find_or_last(|&x| x > 5), None);
1770+
/// ```
1771+
fn find_or_last<P>(mut self, mut predicate: P) -> Option<Self::Item>
1772+
where Self: Sized,
1773+
P: FnMut(&Self::Item) -> bool,
1774+
{
1775+
let mut prev = None;
1776+
self.find_map(|x| if predicate(&x) { Some(x) } else { prev = Some(x); None })
1777+
.or(prev)
1778+
}
1779+
/// Find the value of the first element satisfying a predicate or return the first element, if any.
1780+
///
1781+
/// The iterator is not advanced past the first element found.
1782+
///
1783+
/// ```
1784+
/// use itertools::Itertools;
1785+
///
1786+
/// let numbers = [1, 2, 3, 4];
1787+
/// assert_eq!(numbers.iter().find_or_first(|&&x| x > 5), Some(&1));
1788+
/// assert_eq!(numbers.iter().find_or_first(|&&x| x > 2), Some(&3));
1789+
/// assert_eq!(std::iter::empty::<i32>().find_or_first(|&x| x > 5), None);
1790+
/// ```
1791+
fn find_or_first<P>(mut self, mut predicate: P) -> Option<Self::Item>
1792+
where Self: Sized,
1793+
P: FnMut(&Self::Item) -> bool,
1794+
{
1795+
let first = self.next()?;
1796+
Some(if predicate(&first) {
1797+
first
1798+
} else {
1799+
self.find(|x| predicate(&x)).unwrap_or(first)
1800+
})
1801+
}
17601802
/// Returns `true` if the given item is present in this iterator.
17611803
///
17621804
/// This method is short-circuiting. If the given item is present in this

0 commit comments

Comments
 (0)