TransWikia.com

How to access index in position method of iter?

Stack Overflow Asked by GirkovArpa on February 26, 2021

I’m trying to print the first number in the array that isn’t exactly 1 greater than the previous number (expected result is 7 in the following example).

I wrote &n > 0 && to avoid checking the (non-existent) number before the first number.

fn main() {
    let numbers = [4, 5, 7];
    let result = numbers.iter().position(|&n| &n > 0 && n != numbers[&n - 1] + 1);
    println!("{:?}", result);
}

I get this compiler error regarding the 0:

expected reference, found integer

help: consider borrowing here: &0

Basically I’m trying to do what this JavaScript does:

numbers.find((n, i) => i && n != numbers[i - 1] + 1);

Can someone tell me what I’m doing wrong?

I’m assuming that n is the value and &n is the index. If that isn’t correct then how do I get the index inside the lamba?

4 Answers

Another way to look at each pair of two consecutive items in a slice the windows(2) iterator:

fn find_non_consecutive(a: &[i32]) -> Option<i32> {
    a.windows(2).find(|x| x[0] + 1 != x[1]).map(|x| x[1])
}

Correct answer by Sven Marnach on February 26, 2021

I struggled hard to create a separate function that could be used as I wanted, so here is what ended up working:

fn find_non_consecutive(array_of_numbers: &[i32; 3]) -> Option<i32> {
    let result = array_of_numbers.iter().enumerate().find_map(|(i, &n)| {
        if i > 0 && n != array_of_numbers[i - 1] + 1 {
            Some(n)
        } else {
            None
        }
    });
    return result;
}

fn main() {
    let numbers: [i32; 3] = [4, 5, 7];
    let result = find_non_consecutive(&numbers);
    println!("{:?}", result); // Some(7)
}

Answered by GirkovArpa on February 26, 2021

If you take a look at the signature of Iterator::position, you will see that its predicate closure parameter implements FnMut(Self::Item) -> bool.

In other words, your argument &n is of type <numbers.iter() as Iterator>::Item i.e. &i32 (a reference to an element of numbers). Iterator::position does not provide its predicate closure with access to the iteration index—as Psidom has demonstrated, that's what Iterator::enumerate does.

However, I would suggest that indexing the numbers array is not a very idiomatic way to solve this problem. If nothing else, it can't be applied to other iterables more generally. Perhaps instead take two iterators over the array, one an element further along, zip them up and pairwise compare their elements?

fn main() {
    let numbers = [4, 5, 7];
    
    let first = numbers.iter();
    let second = numbers.iter().skip(1);
    
    let result = first.zip(second)
        .find_map(|(&a, &b)| if b == a + 1 { None } else { Some(b) });
    
    println!("{:?}", result);
}

See it on the playground.

Answered by eggyal on February 26, 2021

position is used to search element. Since you need to check all elements in the array, use enumerate instead to access the element index and value:

fn main() {
    let numbers = [4, 5, 7];
    let result = numbers.iter().enumerate().filter_map(|(i, &n)| {
        if i > 0 && n != numbers[i-1] + 1 {
            Some(n)
        } else {
            None
        }
    });
    println!("{:?}", result.collect::<Vec<i32>>());
}

Playground.

If you only need to find the first such element, you can use find_map instead of filter_map:

fn main() {
    let numbers = [4, 5, 7];
    let result = numbers.iter().enumerate().find_map(|(i, &n)| {
        if i > 0 && n != numbers[i-1] + 1 {
            Some(n)
        } else {
            None
        }
    });
    println!("{:?}", result);
}

Answered by Psidom on February 26, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP