diff --git a/src/iter/mod.rs b/src/iter/mod.rs
index 35f3f0e94..fce24e884 100644
--- a/src/iter/mod.rs
+++ b/src/iter/mod.rs
@@ -1504,7 +1504,7 @@ pub trait ParallelIterator: Sized + Send {
/// just want the first match that discovered anywhere in the iterator,
/// `find_any` is a better choice.
///
- /// # Exmaples
+ /// # Examples
///
/// ```
/// use rayon::prelude::*;
@@ -1551,6 +1551,99 @@ pub trait ParallelIterator: Sized + Send {
find_first_last::find_last(self, predicate)
}
+ /// Applies the given predicate to the items in the parallel iterator
+ /// and returns **any** non-None result of the map operation.
+ ///
+ /// Once a non-None value is produced from the map operation, we will
+ /// attempt to stop processing the rest of the items in the iterator
+ /// as soon as possible.
+ ///
+ /// Note that this method only returns **some** item in the parallel
+ /// iterator that is not None from the map predicate. The item returned
+ /// may not be the **first** non-None value produced in the parallel
+ /// sequence, since the entire sequence is mapped over in parallel.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use rayon::prelude::*;
+ ///
+ /// let c = ["lol", "NaN", "5", "5"];
+ ///
+ /// let first_number = c.par_iter().find_map_first(|s| s.parse().ok());
+ ///
+ /// assert_eq!(first_number, Some(5));
+ /// ```
+ fn find_map_any
(self, predicate: P) -> Option
+ where
+ P: Fn(Self::Item) -> Option + Sync + Send,
+ R: Send,
+ {
+ self.filter_map(predicate).find_any(|_| true)
+ }
+
+ /// Applies the given predicate to the items in the parallel iterator and
+ /// returns the sequentially **first** non-None result of the map operation.
+ ///
+ /// Once a non-None value is produced from the map operation, all attempts
+ /// to the right of the match will be stopped, while attempts to the left
+ /// must continue in case an earlier match is found.
+ ///
+ /// Note that not all parallel iterators have a useful order, much like
+ /// sequential `HashMap` iteration, so "first" may be nebulous. If you
+ /// just want the first non-None value discovered anywhere in the iterator,
+ /// `find_map_any` is a better choice.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use rayon::prelude::*;
+ ///
+ /// let c = ["lol", "NaN", "2", "5"];
+ ///
+ /// let first_number = c.par_iter().find_map_first(|s| s.parse().ok());
+ ///
+ /// assert_eq!(first_number, Some(2));
+ /// ```
+ fn find_map_first(self, predicate: P) -> Option
+ where
+ P: Fn(Self::Item) -> Option + Sync + Send,
+ R: Send,
+ {
+ self.filter_map(predicate).find_first(|_| true)
+ }
+
+ /// Applies the given predicate to the items in the parallel iterator and
+ /// returns the sequentially **last** non-None result of the map operation.
+ ///
+ /// Once a non-None value is produced from the map operation, all attempts
+ /// to the left of the match will be stopped, while attempts to the right
+ /// must continue in case a later match is found.
+ ///
+ /// Note that not all parallel iterators have a useful order, much like
+ /// sequential `HashMap` iteration, so "first" may be nebulous. If you
+ /// just want the first non-None value discovered anywhere in the iterator,
+ /// `find_map_any` is a better choice.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use rayon::prelude::*;
+ ///
+ /// let c = ["lol", "NaN", "2", "5"];
+ ///
+ /// let first_number = c.par_iter().find_map_last(|s| s.parse().ok());
+ ///
+ /// assert_eq!(first_number, Some(5));
+ /// ```
+ fn find_map_last(self, predicate: P) -> Option
+ where
+ P: Fn(Self::Item) -> Option + Sync + Send,
+ R: Send,
+ {
+ self.filter_map(predicate).find_last(|_| true)
+ }
+
#[doc(hidden)]
#[deprecated(note = "parallel `find` does not search in order -- use `find_any`, \\
`find_first`, or `find_last`")]
diff --git a/src/iter/plumbing/README.md b/src/iter/plumbing/README.md
index 8677369ae..cd94eae30 100644
--- a/src/iter/plumbing/README.md
+++ b/src/iter/plumbing/README.md
@@ -140,7 +140,7 @@ such as string characters.
## What on earth is `ProducerCallback`?
We saw that when you call a parallel action method like
-`par_iter.reduce()`, that will creating a "reducing" consumer and then
+`par_iter.reduce()`, that will create a "reducing" consumer and then
invoke `par_iter.drive_unindexed()` (or `par_iter.drive()`) as
appropriate. This may create yet more consumers as we proceed up the
parallel iterator chain. But at some point we're going to get to the
diff --git a/src/iter/test.rs b/src/iter/test.rs
index 069436a7b..900de5add 100644
--- a/src/iter/test.rs
+++ b/src/iter/test.rs
@@ -1271,6 +1271,50 @@ pub fn find_first_or_last() {
assert_eq!(a.par_iter().position_last(|&x| x < 0), None);
}
+#[test]
+pub fn find_map_first_or_last_or_any() {
+ let mut a: Vec = vec![];
+
+ assert!(a.par_iter().find_map_any(half_if_positive).is_none());
+ assert!(a.par_iter().find_map_first(half_if_positive).is_none());
+ assert!(a.par_iter().find_map_last(half_if_positive).is_none());
+
+ a = (-1024..-3).collect();
+
+ assert!(a.par_iter().find_map_any(half_if_positive).is_none());
+ assert!(a.par_iter().find_map_first(half_if_positive).is_none());
+ assert!(a.par_iter().find_map_last(half_if_positive).is_none());
+
+ assert!(a.par_iter().find_map_any(half_if_negative).is_some());
+ assert_eq!(
+ a.par_iter().find_map_first(half_if_negative),
+ Some(-512_i32)
+ );
+ assert_eq!(a.par_iter().find_map_last(half_if_negative), Some(-2_i32));
+
+ a.append(&mut (2..1025).collect());
+
+ assert!(a.par_iter().find_map_any(half_if_positive).is_some());
+ assert_eq!(a.par_iter().find_map_first(half_if_positive), Some(1_i32));
+ assert_eq!(a.par_iter().find_map_last(half_if_positive), Some(512_i32));
+
+ fn half_if_positive(x: &i32) -> Option {
+ if *x > 0 {
+ Some(x / 2)
+ } else {
+ None
+ }
+ }
+
+ fn half_if_negative(x: &i32) -> Option {
+ if *x < 0 {
+ Some(x / 2)
+ } else {
+ None
+ }
+ }
+}
+
#[test]
pub fn check_find_not_present() {
let counter = AtomicUsize::new(0);