About the use of Iterator

    let mut count = 0;
    for i in 2..100 {
        for n in 2..(i + 1) {
            if n == i {
                println!("{}",n);
                count += 1;
            }
            if i % n == 0 && n < i {
                break;
            }
        }
    }
    println!("{}", count);

This is a logic for calculating prime numbers and I don't know how to break, I see break handled in the try_fold() method but I don't seem to see it in the other methods, is it ok to use try_fold() here? Or is there a better way? Suppose I need to use break and continue several times, u even break 'label and continue 'label, is it not appropriate to use Iterator, instead I should use for loops?

What is wrong with using loops here in the first place? If you need to have the functionality of break and continue (which only work inside of loop bodies, not inside of callbacks you pass to the various iterator methods, as you've already stated in your question), why make this program harder to comprehend by using iterator methods instead of loop expressions?

While I do agree with @jofas about the for loops looking cleaner, it is still possible to do what you asked with iterators.

let mut count = 0;

// Iterate over i
(2..100)
    .flat_map(|i| {
        // Flatten with iterator over n
        // See link for explanation
        (2..i + 1).map(move |n| (i, n)).map_while(|(i, n)| {
            // "break" once condition is met. We don't check for i == n yet
            if i % n == 0 && n < i {
                None
            } else {
                Some((i, n))
            }
        })
    })
    // Remove all items where n != i, yield n
    .filter_map(|(i, n)| if n == i { Some(n) } else { None })
    // Print each prime number and increment count
    .for_each(|x| {
        println!("{}", x);
        count += 1;
    });

println!("{}", count);

Unlike your method, this one checks if n == i after it checks for i % n == 0 && n < i. It also uses flat_map to combine multiple for loops into one iterator. (Please see this post.)

If you need a more general solution for breaking out of iterators, please see ControlFlow, try_for_each, and map_while.

I hope this helps! Feel free to respond if you need anything else. (Iterators can be confusing :slight_smile:)

3 Likes

Nice use of Iterator, doesn't look as badly as I thought.

Just nitpicks, but you could simplify this line:

to:

(2..=i).map_while(move |n| { ... }

and move i into that closure instead of creating tuples of (i, n) first.

Also your if statements can be simplified with bool::then_some.

Then this line:

looks a bit cleaner IMO written as:

.filter_map(|(i, n)| (n == i).then_some(n))

and

would become a one-liner (boolean logic must reversed though):

(i % n != 0 || n == i).then_some((i, n))

Here a snippet with these changes:

1 Like

The mutation of external state in for_each() is also weird; it can also be removed using count and inspect.

5 Likes

This is beautiful declarative programming

2 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.