Why does calling filter on a vector not remove ele

2019-08-26 07:31发布

I am writing a small program that finds a winner of a marathon. Everything seems logical until I try to filter the vector for runners that are late for some amount of time. The vector remains same after the filter function, and if use iter_mut() it states type errors.

fn main() {
    let mut input_line = String::new();
    std::io::stdin().read_line(&mut input_line);
    let n = input_line.trim().parse::<u8>().unwrap();
    let mut v = Vec::with_capacity(n as usize);
    for _ in 0..n {
        let mut input_line = String::new();
        std::io::stdin().read_line(&mut input_line);
        let separated = input_line.trim().split(":").collect::<Vec<_>>();
        let hours = separated[0].parse::<u8>().unwrap();
        let minutes = separated[1].parse::<u8>().unwrap();
        let seconds = separated[2].parse::<u8>().unwrap();
        v.push((hours, minutes, seconds));
    }

    //println!("{:?}", v);
    filter_hours(&mut v);
    filter_minutes(&mut v);
    filter_seconds(&mut v);
    println!("{:?}", v[0]);

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

fn filter_hours(v: &mut Vec<(u8, u8, u8)>) {
    let (mut minimum, _, _) = v[0];
    for &i in v.iter() {
        let (h, _, _) = i;
        if h < minimum {
            minimum = h;
        }
    }
    v.iter().filter(|&&(h, _, _)| h == minimum);
}

fn filter_minutes(v: &mut Vec<(u8, u8, u8)>) {
    let (_, mut minimum, _) = v[0];
    for &i in v.iter() {
        let (_, m, _) = i;
        if m < minimum {
            minimum = m;
        }
    }
    v.iter().filter(|&&(_, m, _)| m == minimum);
}

fn filter_seconds(v: &mut Vec<(u8, u8, u8)>) {
    let (_, _, mut minimum) = v[0];
    for &i in v.iter() {
        let (_, _, s) = i;
        if s < minimum {
            minimum = s;
        }
    }
    v.iter().filter(|&&(_, _, s)| s == minimum);
}

2条回答
爷、活的狠高调
2楼-- · 2019-08-26 08:08

Note that filter operates on an iterator, not on the vector; it removes elements from the iterator and not from the vector. One way to do what you want is to collect the result of filter into a new vector and replace the old one with it: v = v.iter().filter(whatever).collect(); but this will allocate space for a new vector, copy the elements from the old vector into the new one, then free the old vector.

There is an experimental API, drain_filter, which allows you to modify the vector and remove matching elements in place. However since it is experimental, this API is only available in nightly for the time being.

If you want to keep to stable Rust and avoid the overhead of collect, you will need to remove the elements by hand. Something like this should do it (taken from the drain_filter docs):

let mut i = 0;
while i != vec.len() {
    if some_predicate(&mut vec[i]) {
        let val = vec.remove(i);
        // your code here
    } else {
        i += 1;
    }
}
查看更多
相关推荐>>
3楼-- · 2019-08-26 08:15

Iterators do not alter the number of items in the original data structure. Instead, you want to use retain:

fn filter_hours(v: &mut Vec<(u8, u8, u8)>) {
    let min = v.iter().map(|&(h, _, _)| h).min().unwrap();
    v.retain(|&(h, _, _)| h == min);
}
查看更多
登录 后发表回答