Skip to content

Commit

Permalink
Merge #535
Browse files Browse the repository at this point in the history
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 <linusbehrbohm@web.de>
  • Loading branch information
bors[bot] and mankinskin committed May 4, 2021
2 parents b87fc76 + 086b7d2 commit 271a341
Showing 1 changed file with 43 additions and 1 deletion.
44 changes: 43 additions & 1 deletion src/lib.rs
Expand Up @@ -1756,7 +1756,49 @@ pub trait Itertools : Iterator {
}
None
}

/// Find the value of the first element satisfying a predicate or return the last element, if any.
///
/// The iterator is not advanced past the first element found.
///
/// ```
/// use itertools::Itertools;
///
/// let numbers = [1, 2, 3, 4];
/// assert_eq!(numbers.iter().find_or_last(|&&x| x > 5), Some(&4));
/// assert_eq!(numbers.iter().find_or_last(|&&x| x > 2), Some(&3));
/// assert_eq!(std::iter::empty::<i32>().find_or_last(|&x| x > 5), None);
/// ```
fn find_or_last<P>(mut self, mut predicate: P) -> Option<Self::Item>
where Self: Sized,
P: FnMut(&Self::Item) -> bool,
{
let mut prev = None;
self.find_map(|x| if predicate(&x) { Some(x) } else { prev = Some(x); None })
.or(prev)
}
/// Find the value of the first element satisfying a predicate or return the first element, if any.
///
/// The iterator is not advanced past the first element found.
///
/// ```
/// use itertools::Itertools;
///
/// let numbers = [1, 2, 3, 4];
/// assert_eq!(numbers.iter().find_or_first(|&&x| x > 5), Some(&1));
/// assert_eq!(numbers.iter().find_or_first(|&&x| x > 2), Some(&3));
/// assert_eq!(std::iter::empty::<i32>().find_or_first(|&x| x > 5), None);
/// ```
fn find_or_first<P>(mut self, mut predicate: P) -> Option<Self::Item>
where Self: Sized,
P: FnMut(&Self::Item) -> bool,
{
let first = self.next()?;
Some(if predicate(&first) {
first
} else {
self.find(|x| predicate(&x)).unwrap_or(first)
})
}
/// Returns `true` if the given item is present in this iterator.
///
/// This method is short-circuiting. If the given item is present in this
Expand Down

0 comments on commit 271a341

Please sign in to comment.