【问题标题】:Doing more than 1 thing in a iter().map()在 iter().map() 中做不止一件事
【发布时间】:2022-01-13 11:42:15
【问题描述】:

我想使用地图来创建一个新矢量,但同时在该地图内做其他事情。我正在编写 Advent of Code 2021,第 6 天第 1 部分。

此代码循环遍历一个向量并将所有值减一。如果该值位于0,则它将该位置重置为6,并将8 添加到向量的末尾。

fn run_growth_simulation(mut state: Vec<u8>, days: i32) -> usize {
    for _day in 0..days {
        let mut new_fish = 0;
        state.iter_mut().map(|x| match x {
            num: u8 @ 1..=8 => {num - 1},
            0 => {new_fish += 1; 6},
            _ => unreachable!()
        })

        for _fish in 0..new_fish {
            state.push(8);
        }
    }
    state.iter().count() as usize
}

我如何从关闭中返回正确的项目?

【问题讨论】:

    标签: rust iterator


    【解决方案1】:

    我会直接改变迭代器中的值而不是构建新数组,因为使用for_each 而不是map(或首选直接使用for循环)。 然后在 match 语句中改变值:

    state.iter_mut().for_each(|x| match x {
                 //: u8 removed because it gave me an syntax error
                                // mutate the number directly (we have to use `num` because x was moved)
                num @ 1..=8 => {*num -= 1;},
                                     // mutate the number
                0 => {new_fish += 1; *x = 6;},
                _ => unreachable!()
            });
    

    一种稍微不同的方法是计算向量中的0s,删除它们,将每个值减去 1 并添加新的鱼

    【讨论】:

      【解决方案2】:

      作为对for_each()map() 更可取的答案的补充(因为我们不消耗map() 发出的内容),下面是一个更简单的示例,试图说明问题(以及为什么借用-checker 在禁止此类尝试时是正确的)。 在这两种情况下(test1()test2()),我们在扩展向量的同时迭代它(这是问题中的意图)。

      test1() 中,迭代器在创建时会一次性考虑值的存储。 对于所有后续迭代,它将引用此初始存储,因此此存储同时不得移动到内存中的其他位置。 这就是迭代器借用向量的原因(可变与否,这在这里并不重要)。 然而,在这些迭代过程中,我们尝试将新值附加到该向量:这可能会移动存储空间(出于重新分配目的)并且幸运的是这需要向量的可变借用(然后它被拒绝)。

      test2() 中,我们避免保留对初始存储的引用,而是使用计数器。 这行得通,但这是次优的,因为在每次迭代中,此索引操作 ([]) 都需要检查边界。 前一个函数中的迭代器知道所有的边界;这就是为什么迭代器会为编译器带来更好的优化机会。 请注意,len() 在循环开始时被评估一次;这可能是我们想要的,但如果我们想在每次迭代中重新评估它,那么我们将不得不使用loop {} 指令。

      这里讨论的不是特定于语言,而是特定于问题本身。 使用更宽松的编程语言,第一次尝试可能是允许的,但会导致内存错误;或者这样的语言应该系统地转向第二次尝试,并在每次迭代时支付边界检查的成本。

      最后,带有第二个循环的解决方案可能是最好的选择。

      fn test1() {
          let mut v = vec![1, 2, 3, 4, 5, 6, 7, 8];
          v.iter_mut().for_each(|e| {
              if *e <= 3 {
                  let n = *e + 100;
                  // v.push(n) // !!! INCORRECT !!!
                  // we are trying to reallocate the storage while iterating over it
              } else {
                  *e += 10;
              }
          });
          println!("{:?}", v);
      }
      
      fn test2() {
          let mut v = vec![1, 2, 3, 4, 5, 6, 7, 8];
          for i in 0..v.len() {
              let e = &mut v[i];
              if *e <= 3 {
                  let n = *e + 100;
                  v.push(n);
              } else {
                  *e += 10;
              }
          }
          println!("{:?}", v);
      }
      
      fn main() {
          test1(); // [1, 2, 3, 14, 15, 16, 17, 18]
          test2(); // [1, 2, 3, 14, 15, 16, 17, 18, 101, 102, 103]
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-11-08
        • 2018-08-27
        • 1970-01-01
        • 1970-01-01
        • 2011-02-02
        • 2020-05-01
        • 2021-03-02
        相关资源
        最近更新 更多