Combine Filter to include and Exclude
The vec! macro

Before we have a look at including and excluding, we should note that

let mut myvec: Vec&lt;T&gt; = Vec::with_capacity(2);
myvec.push(a);
myvec.push(b);
myvec.push(c);


can be written with the vec! macro as

let myvec: Vec&lt;T&gt; = vec![a,b,c];


This has the nice side-effect that myvec doesn't need to be mut anymore. If we apply this too all your code, we end up with    

#[derive(Debug)]
pub struct Dataset {
    pub data: Vec&lt;String&gt;,
}
fn main() {
    //setup test data
    let ds1_data = vec!["a".to_string(), "b".to_string()];
    let ds1 = Dataset { data: ds1_data };

    let ds2_data = vec!["a".to_string(), "c".to_string()];
    let ds2 = Dataset { data: ds2_data };

    let datasets = vec![ds1, ds2];

    let include = vec!["a".to_string()];
    let exclude = vec!["b".to_string()];

    //filter datasets
    for ds in datasets {
        if ds.data.iter().find(|d| include.contains(d)).is_none() {
            continue;
        }
        if ds.data.iter().find(|d| exclude.contains(d)).is_some() {
            continue;
        }

        println!("{:?}", ds);
    }
}


That's a lot less noise, perfect to concentrate on the original problem.

Including and excluding

First of all, instead of find(…).is_some(), we can use any, and instead of find(…).is_none() too. We could use that to simplify the expressions, but we would still traverse the set twice.

for ds in datasets {
    if !ds.data.iter().any(|d| include.contains(d)) {
        //skip not included
        continue;
    }        
    if ds.data.iter().any(|d| exclude.contains(d)) {
        //skip excluded
        continue;
    }

    println!("{:?}", ds);
}


Instead, let's think about the elements we have to look at. The answer is all, as exclude might match the last element in our dataset, even if include matched the first.

As we have to look at all elements either way, we might as well traverse them by hand:

    for ds in datasets {
        let mut included = false;
        let mut excluded = false;
        for d in &amp;ds.data {
            if included == false &amp;&amp; include.contains(d) {
                included = true;
            }
            if exclude.contains(d) {
                excluded = true;
                break;
            }
        }
        if included == false || excluded == true {
            continue;
        }

        println!("{:?}", ds);
    }


Now that we have this as a blueprint, we can check the iterators for a fitting method. We need to


check that at least one include matches
check that no exclude matches
stop as soon as soon as any exclude matches.


Unfortunately it's not possible to quick exit from a closure, so the last requirement cannot be done with fold or similar. However, we can use inspect and all to get something like our previous loop:

    for ds in datasets {
        let mut included = false;

        if !ds
            .data
            .iter()
            .inspect(|d| {
                if included == false || include.contains(d) {
                    included = true
                }
            })
            .all(|d| !exclude.contains(d))
            || !included
        {
            continue;
        }
        println!("{:?}", ds);
    }


But that's a lot less readable than our previous loop, which did the same. We could increase readablity if we introduced a function, but that's left as an exercise. In the end, we would need a fold-like function that supports an early exit, but such a function does not exist.