我正在编写一个Rust函数,该函数接受一个数字列表和一个最大值,并将给定数字的所有倍数加总到最大(重复项仅计算一次)。我编写的函数的第一个版本是
use std::collections::HashSet;
pub fn sum_of_multiples(limit: u32, factors: &[u32]) -> u32 {
let set: HashSet<u32> = factors
.iter()
.map(|factor| {
let top: u32 = (limit - 1) / factor;
(1..=top).map(move |num| num * factor)
}).flatten()
.collect();
set.iter().fold(0, |acc, num| acc + num)
}
(我知道像这样合并HashSets
可能不是最佳解决方案)。这样可以得到预期的结果:
println!("{}", sum_of_multiples(100, &[3, 5])) // 2318
当我在中间拨出对collect
的呼叫并链接最后一个fold
时,我得到一个不同的答案:
pub fn sum_of_multiples(limit: u32, factors: &[u32]) -> u32 {
let val: u32 = factors
.iter()
.map(|factor| {
let top: u32 = (limit - 1) / factor;
(1..=top).map(move |num| num * factor)
}).flatten()
.fold(0, |acc, num| acc + num);
val
}
结果:
println!("{}", sum_of_multiples(100, &[3, 5])) // 2633
我知道迭代器是延迟计算的,但是我假设它们是按使用顺序依次评估的。是因为flatten
与HashSet
的行为?我不明白为什么第二轮结果不同,或者2633的意义(如果有)是什么。
答案 0 :(得分:5)
您没有在第二个片段中删除重复项,因为您直接消耗了迭代器。
(我知道像这样合并
HashSet
可能不是最佳解决方案)。
由于需要临时存储来删除重复项,因此可以使用Vec
然后将其放入集合中,或者可以使用Vec
排序并过滤重复值来代替集合自己,但这需要测试。
这个也应该测试。这使您不必担心其实现方式。
最后,您可以在一个表达式中编写函数:
use std::collections::HashSet;
pub fn sum_of_multiples(limit: u32, factors: &[u32]) -> u32 {
factors
.iter()
.flat_map(|factor| {
let top = (limit - 1) / factor;
(1..=top).map(move |num| num * factor)
})
.collect::<HashSet<u32>>()
.iter()
.sum()
}
答案 1 :(得分:4)
根据原始的要求说明,您已经删除了实际上用于某个目的的中间HashSet
:
重复项仅计算一次
省去了将值存储在HashSet
中的步骤,这意味着将在每次出现重复项时对其进行计数,这应该可以解释差异。