Rustlings中迭代器不同方案比较

113 阅读3分钟

在 Rust 中,迭代器是一种强大的工具,可以帮助我们以更简洁、高效的方式处理集合数据。本文将探讨如何通过迭代器优化两个计数函数:count_iterator 和 count_collection_iterator。我们将分析不同的实现方案,并最终选择最优的解决方案。

1. 函数功能描述

count_collection_iterator 函数

  • 功能:统计一个 HashMap<String, Progress> 切片中特定 Progress 值的总出现次数。

  • 参数

    • collection: &[HashMap<String, Progress>]:一个包含多个 HashMap 的切片。
    • value: Progress:需要统计的目标值。
  • 返回值usize,表示目标值在集合中出现的总次数。

示例

let collection = vec![
    HashMap::from([("variables1".to_string(), Progress::Complete)]),
    HashMap::from([("variables2".to_string(), Progress::None)]),
];
let count = count_collection_iterator(&collection, Progress::Complete);
assert_eq!(count, 1);
count_iterator 函数
fn count_iterator(map: &HashMap<String, Progress>, value: Progress) -> usize {
    map.values().filter(|&x| *x == value).count()
}

2. 五种实现方案

方案一:使用 map 和 sum

fn count_collection_iterator(collection: &[HashMap<String, Progress>], value: Progress) -> usize {
    collection
        .iter()
        .map(|map| count_iterator(map, value))
        .sum()
}

分析

  • map:对每个 HashMap 调用 count_iterator,计算其中目标值的数量。
  • sum:将所有 HashMap 的计数结果相加。
  • 优点:代码简洁,逻辑清晰。
  • 缺点:需要为每个 HashMap 单独调用 count_iterator,可能存在性能开销。

方案二:使用 fold

fn count_collection_iterator(collection: &[HashMap<String, Progress>], value: Progress) -> usize {
    collection
        .iter()
        .fold(0, |acc, map| acc + count_iterator(map, value))
}

分析

  • fold:通过累加器 acc 手动累加每个 HashMap 的计数结果。
  • 优点:避免了中间集合的创建,性能较好。
  • 缺点:代码略显冗长,可读性稍差。

方案三:使用 map 和 flatten

fn count_collection_iterator(collection: &[HashMap<String, Progress>], value: Progress) -> usize {
    collection
        .iter()
        .map(|map| map.values())
        .flatten()
        .filter(|&x| *x == value)
        .count()
}

分析

  • map:将每个 HashMap 转换为值的迭代器。
  • flatten:将多个迭代器合并为一个扁平化的迭代器。
  • filter 和 count:过滤并统计目标值的数量。
  • 优点:代码简洁,逻辑清晰。
  • 缺点flatten 可能会引入额外的性能开销。

方案四:使用 flat_map

fn count_collection_iterator(collection: &[HashMap<String, Progress>], value: Progress) -> usize {
    collection
        .iter()
        .flat_map(|map| map.values())
        .filter(|&x| *x == value)
        .count()
}

分析

  • flat_map:将每个 HashMap 的值直接合并为一个迭代器。
  • filter 和 count:过滤并统计目标值的数量。
  • 优点:代码简洁,性能高效。
  • 缺点:无显著缺点,是推荐的实现方式。

方案五:使用 map 和 filter 内联

fn count_collection_iterator(collection: &[HashMap<String, Progress>], value: Progress) -> usize {
    collection
        .iter()
        .map(|map| map.values().filter(|&x| *x == value).count())
        .sum()
}

分析

  • map:对每个 HashMap 进行映射,计算其中目标值的数量。
  • sum:将所有 HashMap 的计数结果相加。
  • 优点:代码简洁,逻辑清晰。
  • 缺点:需要为每个 HashMap 单独调用 filter 和 count,可能存在性能开销。

3. 方案对比与选择

方案代码简洁性性能可读性推荐度
方案一⭐⭐⭐
方案二⭐⭐
方案三⭐⭐⭐
方案四⭐⭐⭐⭐
方案五⭐⭐⭐

最优方案:方案四

  • 推荐理由

    • 代码简洁,逻辑清晰。
    • 性能高效,避免了不必要的中间步骤。
    • 符合 Rust 的函数式编程风格。

最终实现

fn count_collection_iterator(collection: &[HashMap<String, Progress>], value: Progress) -> usize {
    collection
        .iter()
        .flat_map(|map| map.values())
        .filter(|&x| *x == value)
        .count()
}

4. 知识点总结

迭代器方法

  1. map:对每个元素进行映射转换。
  2. filter:过滤出满足条件的元素。
  3. flatten:将嵌套的迭代器扁平化。
  4. flat_map:将每个元素映射为一个迭代器并扁平化。
  5. fold:通过累加器手动累加结果。
  6. sum:对迭代器的所有元素求和。

适用场景

  • map + sum:适合需要对每个元素进行独立计算的场景。
  • flat_map:适合需要将多个迭代器合并为一个的场景。
  • fold:适合需要手动控制累加逻辑的场景。