Multiple staggered filters on an iterator

Say I have a Vec of words called words and a fn get_char() -> Result<char> that gets a char from stdin.
I want to run .filter(|word| !(**word).contains(guess)) everytime I get a new char but having some trouble doing so. Here's what I've attempted:

let filtered = words.iter();
for _ in 0..10 {
    let guess = get_char().unwrap();
    filtered = filtered.filter(|word| !(**word).contains(guess));
}

But of course the compiler complains that the result of filtered.filter() is a Filter and not an Iter. What's the best way to work around it?

I would do this:

let mut filters = Vec::new();
for _ in 0..10 {
    let guess = get_char().unwrap();
    filters.push(guess);
}

let filtered = words.iter().filter(move |word| {
    for guess in &filters {
        if !(**word).contains(guess) {
            return false;
        }
    }
    true
});

That works, but I want to do something after every guess. Perhaps I should've wrote it like this:

let filtered = words.iter();
for _ in 0..10 {
    let guess = get_char().unwrap();
    filtered = filtered.filter(|word| !(**word).contains(guess));
    // do something with the filtered list before the next guess
}

Can be shortened to:

let mut filters = Vec::new();
for _ in 0..10 {
    let guess = get_char().unwrap();
    filters.push(guess);
}

let filtered = words
    .iter()
    .filter(|word| !filters.iter().any(|guess| word.contains(guess)));

Again, that doesn't really answer my question

You can box the iterators

let mut filtered: Box<dyn Iterator<Item = &str> + '_> = Box::new(words.iter().copied());
for _ in 0..10 {
    let guess = get_char().unwrap();
    filtered = Box::new(filtered.filter(move |word| !(**word).contains(guess)));
}

Thank you!

filter() is lazy, so you won't do anything after every guess. You can use trait objects, but I think the right approach here is not that.

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.