rustiteratorpositionrust-itertools

Is there an iterator method that takes a predicate and gives back an index and the matching element?


I am searching for something like this:

let iter = vec![1, 2, 40, 3].into_iter();
let (pos, elt) = iter.position_find(|&x| x > 10);
//                    ^ does not exist

println!("{pos} {elt}"); // 2 40

Both Iterator::position and Iterator::find advance the iterator, so I can't use both unless I'm cloning the iterator, which is unnecessary here.


Solution

  • You can use find together with enumerate:

    let iter = vec![1, 2, 40, 3].into_iter();
    if let Some((pos, elt)) = iter.enumerate().find(|(i, x)| x > &10) {
        println!("{pos} {elt}"); // 2 40
    }
    

    If you don't want to write this out every time, you could even turn it into an extension trait to automatically implement it as a method on all iterators:

    trait FindPosition: Iterator {
        fn find_position<F: FnMut(usize, &Self::Item) -> bool>(
            &mut self,
            mut f: F,
        ) -> Option<(usize, Self::Item)> {
            self.enumerate().find(|(i, item)| f(*i, item))
        }
    }
    
    impl<I: Iterator> FindPosition for I {}
    
    fn main() {
        let mut iter = vec![1, 2, 40, 3].into_iter();
        if let Some((pos, elt)) = iter.find_position(|_, x| *x > 10) {
            println!("{pos} {elt}"); // 2 40
        }
    }