Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a parallel equivalent to Iterator::find_map #607

Closed
cuviper opened this issue Oct 25, 2018 · 6 comments
Closed

Add a parallel equivalent to Iterator::find_map #607

cuviper opened this issue Oct 25, 2018 · 6 comments

Comments

@cuviper
Copy link
Member

cuviper commented Oct 25, 2018

Iterator::find_map is now stable in Rust 1.30:

fn find_map<B, F>(&mut self, f: F) -> Option<B>
where
    F: FnMut(Self::Item) -> Option<B>, 

Applies function to the elements of iterator and returns the first non-none result.

iter.find_map(f) is equivalent to iter.filter_map(f).next().

For Iterator::find, we have variants ParallelIterator::{find_any,find_first,find_last}, so the user can be precise whether they care about the order. We should probably do similar for find_map, with some bikeshedding required... find_map_any? find_any_map?

@cuviper
Copy link
Member Author

cuviper commented Oct 25, 2018

I think in our case, the easiest implementation would be something like:
iter.map(f).find_any(Option::is_some).map(Option::unwrap)

@cuviper
Copy link
Member Author

cuviper commented Oct 25, 2018

The actual implementation in Iterator::find_map is:

    fn find_map<B, F>(&mut self, mut f: F) -> Option<B> where
        Self: Sized,
        F: FnMut(Self::Item) -> Option<B>,
    {
        self.try_for_each(move |x| {
            match f(x) {
                Some(x) => LoopState::Break(x),
                None => LoopState::Continue(()),
            }
        }).break_value()
    }

We could do similar if we invent/copy a similar internal LoopState type, but that only works for the any variant. We'd still need something ordered for first/last variants.

@cuviper
Copy link
Member Author

cuviper commented Oct 25, 2018

iter.filter_map(f).find_any(|_| true) should work too, closer to what the docs suggest.

@seanchen1991
Copy link
Contributor

I'm taking a stab at implementing this. @cuviper I was thinking of implementing find_map on top of find_first. With find_any it would seem like it would kind of defeat the purpose of what the sequential version of find_map tries to accomplish according to the docs.

So basically iter.filter_map(f).find_first(|x| x.is_some()).

Does that sound reasonable?

@cuviper
Copy link
Member Author

cuviper commented Jan 16, 2019

I think we will want all of the variants, first, last, and any.

For some background, see the original addition of find (deprecated) and find_any in #129. We knowingly diverged from Iterator::find by not just finding the first match, because this is natural for parallelism that's processing in any order, but we decided this should be reflected in the name find_any. Then in #151/#189 we added the find_first/last variants that do care about order, but you can see that this takes extra bookkeeping to track relative positions.

bors bot added a commit that referenced this issue Feb 19, 2019
627: Add `find_map` with `any`, `first`, and `last` variants r=cuviper a=seanchen1991

PR opened in response to #607. 

633: Update dev and demo dependencies r=cuviper a=cuviper

- `cgmath 0.17`
- `glium 0.23`
- `rand 0.6`

Co-authored-by: Sean <[email protected]>
Co-authored-by: Josh Stone <[email protected]>
@cuviper
Copy link
Member Author

cuviper commented Apr 26, 2019

Done in #627.

@cuviper cuviper closed this as completed Apr 26, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants