rust

Clone any collection by selecting elements based on a criteria


I have a collection(for time being Vec) which I want to clone but having only the elements that specify a criteria. Basically I want the C++ functionality of std::copy_if. I want the below generic code to work for any collection type. If the input collection type is a Vec, I want the output collection type to be also a Vec.

fn clone_if<'a, List, ItemType, BinaryPredicate>(list: List, binary_predicate: BinaryPredicate) -> List
where
    List: Clone + IntoIterator<Item = &'a ItemType> + Copy,
    ItemType: 'a,
    BinaryPredicate: Fn(&ItemType) -> bool
{
    let mut res = list.clone();
    for item in res.into_iter() {
        if !binary_predicate(&item) {
            // res.remove();
        }
    }
    
    res
}

fn main() {
    let first_list = vec![1, 2, 3, 4, 5, 6];
    let second_list = clone_if(&first_list, |item| {
        (item & 1) == 0
    });
    
    assert_eq!(vec![2, 4, 6], *second_list);
}

Solution

  • The current function signature of clone_if is not compatible with what you want to achieve. So I rewrote it slightly to probably match what you actually want.

    Here you go:

    fn clone_if<List, ItemType, BinaryPredicate>(list: &List, binary_predicate: BinaryPredicate) -> List
    where
        for<'a> &'a List: IntoIterator<Item = &'a ItemType>,
        List: FromIterator<ItemType>,
        ItemType: Clone,
        BinaryPredicate: Fn(&ItemType) -> bool,
    {
        list.into_iter()
            .filter(|val| binary_predicate(*val))
            .cloned()
            .collect()
    }
    
    fn main() {
        let first_list = vec![1, 2, 3, 4, 5, 6];
        let second_list = clone_if(&first_list, |item| (item & 1) == 0);
    
        assert_eq!(vec![2, 4, 6], *second_list);
    }
    

    Explanation:

    Then the algorithm itself: