代码之家  ›  专栏  ›  技术社区  ›  Harry

通过根据条件选择元素来克隆任何集合

  •  -1
  • Harry  · 技术社区  · 4 月前

    我暂时有收藏 Vec )我想克隆它,但只有指定条件的元素。基本上,我想要的是C++的功能 std::copy_if 。我希望下面的通用代码适用于任何集合类型。如果输入集合类型为 Vec ,我希望输出集合类型也是 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);
    }
    
    1 回复  |  直到 4 月前
        1
  •  1
  •   Finomnis    4 月前

    当前函数签名 clone_if 与你想要实现的目标不兼容。所以我稍微重写了一下,可能是为了符合你真正想要的。

    干得好:

    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);
    }
    

    说明:

    • list: &List -用你的方式称呼它 main ,你需要一个参考。
    • for<'a> &'a List: IntoIterator<Item = &'a ItemType> -你想要 list 引用在迭代时产生对其元素的引用,这就是 &Vec is compatible with 。这可以防止不必要的复制。
    • List: FromIterator<ItemType> -需要通过以下方式产生输出值 collect() .
    • ItemType: Clone -您希望在输出列表中创建输入项的克隆。
    • 所有其他 Clone Copy s被删除了,因为它们是不必要的。

    然后是算法本身:

    • .into_iter() -创建一个 Iterator<Item = &ItemType> 从您的输入列表中
    • .filter(|val| binary_predicate(*val)) -进行筛选。尚未制作副本。需要闭包和解引用的原因是 filter 引用迭代过的项,在本例中为 &&ItemType 。因此需要一个小包装来转换 &&项目类型 &ItemType ,这就是 binary_predicate 需要。
    • .cloned() -克隆所有迭代过的项目。这将转换 迭代器<项目=&项目类型> 到a Iterator<Item = ItemType> 请注意,此操作已完成 之后 filter() 以防止复制无论如何都会被过滤掉的项目。
    • .collect() 使用 FromIterator 转换 迭代器<项目=项目类型> List .