【问题标题】:Remove only the trailing elements of a Vec that match a condition仅删除匹配条件的 Vec 的尾随元素
【发布时间】:2018-02-07 23:17:56
【问题描述】:

我有一个Vec<T>,其中包含与模式匹配的元素。我想删除与模式匹配的元素的所有尾随实例。

例如,我有一个Vec<i32>,模式是(|x| x == 0)。如果输入为:vec![0, 1, 0, 2, 3, 0, 0],则输出应为:vec![0, 1, 0, 2, 3]

为此我尝试了:

fn main() {
    let mut vec = vec![0, 1, 0, 2, 3, 0, 0];
    vec = vec.into_iter().rev().skip_while(|&x| x == 0).rev();
}

但是我得到了这些编译器错误:

error[E0277]: the trait bound `std::iter::SkipWhile<std::iter::Rev<std::vec::IntoIter<{integer}>>, [closure@src/main.rs:3:44: 3:55]>: std::iter::DoubleEndedIterator` is not satisfied
 --> src/main.rs:3:57
  |
3 |     vec = vec.into_iter().rev().skip_while(|&x| x == 0).rev();
  |                                                         ^^^ the trait `std::iter::DoubleEndedIterator` is not implemented for `std::iter::SkipWhile<std::iter::Rev<std::vec::IntoIter<{integer}>>, [closure@src/main.rs:3:44: 3:55]>`

error[E0308]: mismatched types
 --> src/main.rs:3:11
  |
3 |     vec = vec.into_iter().rev().skip_while(|&x| x == 0).rev();
  |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected struct `std::vec::Vec`, found struct `std::iter::Rev`
  |
  = note: expected type `std::vec::Vec<{integer}>`
             found type `std::iter::Rev<std::iter::SkipWhile<std::iter::Rev<std::vec::IntoIter<{integer}>>, [closure@src/main.rs:3:44: 3:55]>>`

奇怪的是DoubleEndedIterator是为SkipWhile实现的。事实上,SkipWhile 甚至实现了rev()See here.

我做错了什么?有更好的方法吗?

【问题讨论】:

    标签: iterator rust


    【解决方案1】:

    用于反转的迭代器适配器仅适用于可以从任意两端遍历的迭代器(如DoubleEndedIterator)。虽然这是原始版本的情况,但从我们包含 skip_while 的那一刻起就不再可能了。为了遵循这种方法,您必须收集反向向量的其余部分,然后才能再次反向。

    另一方面,我只会选择获取第一个尾随零的索引并用它截断向量。

    let mut vec = vec![0, 1, 0, 2, 3, 0, 0];
    if let Some(i) = vec.iter().rposition(|x| *x != 0) {
        let new_len = i + 1;
        vec.truncate(new_len);
    }
    

    ... 或者只是拿一片来代替:

    let piece = &vec[..new_len];
    

    Playground

    【讨论】:

    • 我喜欢这个解决方案,因为它可能是最节省内存的答案。如果你想保留take_while,你可以使用.take_while(|&amp;&amp;x| x == 0).count()
    • 您可以使用rposition更清楚地表达您的意图。
    • @raggy 谢谢,现在添加了这个调整。
    【解决方案2】:

    如错误消息所述:

    1. 特征 DoubleEndedIterator 没有为 SkipWhile&lt;...&gt; 实现 — 看看 SkipWhile 的实现:

      pub struct SkipWhile<I, P> {
          iter: I,
          flag: bool,
          predicate: P,
      }
      

      您无法反转从SkipWhile 构建的迭代器,因为当您添加从前面和后面拉取的功能时,它无法跟踪“当前”项目是否被跳过。

    2. 预期的结构 Vec,找到结构 Rev — 您仍然有一个迭代器,但您正试图将它存储在必须存储 Vec 的位置。您不能将类型 A 放在需要类型 B 的地方。

    我会collect 向量,然后reverse 就位:

    fn main() {
        let mut vec = vec![0, 1, 0, 2, 3, 0, 0];
    
        vec = vec.into_iter().rev().skip_while(|&x| x == 0).collect();
        vec.reverse();
    
        println!("{:?}", vec);
        assert_eq!(vec, [0, 1, 0, 2, 3]);
    }
    

    DoubleEndedIterator 是为SkipWhile 实现的。

    这不是真的。如果您查看SkipWhile 的文档,它并没有列出它实现了DoubleEndedIterator。以下是它实现的特征示例:FusedIterator

    其实SkipWhile甚至实现了rev()

    实际上并没有。 Iterator::rev 仅在Self(即SkipWhile)实现DoubleEndedIterator 的条件下实现,这不会:

    fn rev(self) -> Rev<Self>
    where
        Self: DoubleEndedIterator, 
    

    【讨论】:

      【解决方案3】:

      只是为了让事情开始,这是一个非常狡猾的解决方案:

      fn main() {
          let mut vec = vec![0, 1, 0, 2, 3, 0, 0];
          vec = vec.into_iter().rev().skip_while(|&x| x == 0).collect();
          vec = vec.into_iter().rev().collect();
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-10-14
        • 2020-03-31
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-11-30
        • 2023-02-09
        相关资源
        最近更新 更多