Coding style 如何将Vec部分折叠到位?

Coding style 如何将Vec部分折叠到位?,coding-style,rust,Coding Style,Rust,我想浏览一个Vec并结合其中的一些元素。在惯用的中如何实现这一点 例子: #[派生(PartialEq,调试)] 枚举对象{A,B,A和B} fn联合收割机(v:Vec)->Vec{ //这里的惯用代码 } fn main(){ 让v=vec![Thing::A,Thing::B]; assert_eq!(vec![Thing::AandB],combine(v)); } 我会怎么做: 使用迭代器::扫描遍历Vec,如果Thing::A是之前的元素,则使用Thing::A和B替换Thing::

我想浏览一个Vec并结合其中的一些元素。在惯用的中如何实现这一点

例子:
#[派生(PartialEq,调试)]
枚举对象{A,B,A和B}
fn联合收割机(v:Vec)->Vec{
//这里的惯用代码
}
fn main(){
让v=vec![Thing::A,Thing::B];
assert_eq!(vec![Thing::AandB],combine(v));
}
我会怎么做: 使用迭代器::扫描遍历Vec,如果Thing::A是之前的元素,则使用Thing::A和B替换Thing::B的所有出现。然后我将再次遍历它并删除所有Thing::像前面一样Thing::AandB


这似乎非常复杂且不雅观。

不确定这是否算作惯用,但该库为所有迭代器提供了
批处理()函数。结合标准库中的
peek()
,您可以在一次迭代而不是两次迭代中获得结果

extern crate itertools;

use itertools::Itertools;
use Thing::*;

#[derive(PartialEq, Debug)]
enum Thing { A, B, AandB }
fn combine(v: Vec<Thing>) -> Vec<Thing> {
    v.into_iter().peekable().batching(|mut it| {
        match it.next() {
            Some(A) => {
                if Some(&B) == it.peek() {
                    it.next();
                    Some(AandB)
                } else {
                    Some(A)
                }
            }
            x => x,
        }
    }).collect()
}

fn main() {
    let v = vec![A, B, A, A, A, B, B, A];
    assert_eq!(
        vec![AandB, A, A, AandB, B, A],
        combine(v)
    );
}
外部板条箱工具;
使用itertools::itertools;
使用事物::*;
#[派生(PartialEq,Debug)]
枚举对象{A,B,A和B}
fn联合收割机(v:Vec)->Vec{
v、 进入iter().peek().batching(| mut it |{
匹配它。下一个(){
一些(A)=>{
如果某些(&B)==it.peek(){
it.next();
一些(A和B)
}否则{
一些(A)
}
}
x=>x,
}
}).collect()
}
fn main(){
设v=vec![A,B,A,A,A,B,B,A];
断言(
向量![AandB,A,A,AandB,B,A],
联合收割机(五)
);
}

显然,
collect()

我怀疑迭代器不容易做到这一点,但没有人禁止使用简单的老式c风格:

#[derive(PartialEq, Debug, Copy)]
enum Thing { A, B, AandB }
fn combine(mut v: Vec<Thing>) -> Vec<Thing> {
    let mut prev: Option<Thing> = None;
    let mut end = 0;
    for i in 0 .. v.len() {
        let el = v[i];
        match (el, prev) {
            (Thing::B, Some(Thing::A)) => {
                end = end - 1;
                v[end] = Thing::AandB
            },
            _ => 
                v[end] = el
        };
        prev = Some(el);
        end = end + 1;
    }

    v.truncate(end);
    v
}

fn main() {
     let v = vec![Thing::A, Thing::A, Thing::B, Thing::AandB, Thing::B, Thing::A];
     assert_eq!(vec![Thing::A, Thing::AandB, Thing::AandB, Thing::B, Thing::A], combine(v));
}
#[派生(部分查询、调试、复制)]
枚举对象{A,B,A和B}
fn联合收割机(mut v:Vec)->Vec{
让mut-prev:Option=None;
设mut-end=0;
对于0..v.len()中的i{
设el=v[i];
匹配(el,上一个){
(事物::B,一些(事物::A))=>{
结束=结束-1;
v[end]=事物::a和b
},
_ => 
v[结束]=el
};
prev=一些(el);
结束=结束+1;
}
v、 截断(结束);
v
}
fn main(){
让v=vec![Thing::A,Thing::A,Thing::B,Thing::A和B,Thing::B,Thing::A];
assert_eq!(vec![Thing::A,Thing::AandB,Thing::AandB,Thing::B,Thing::A],combine(v));
}

这是一个直接转换过程。

这是一个使用递归和模式匹配的解决方案。我很确定递归是尾部递归,因此可以转化为迭代

use Thing::*;

#[derive(Copy,Clone,PartialEq,Debug)]
enum Thing { A, B, AandB }

fn combine(v: Vec<Thing>) -> Vec<Thing> {
    fn inner(mut res: Vec<Thing>, s: &[Thing]) -> Vec<Thing> {
        match s {
            [A, B, tail..] => {
                res.push(AandB);
                inner(res, tail)
            },
            [a, tail..] => {
                res.push(a);
                inner(res, tail)
            },
            [] => res,
        }
    };

    inner(Vec::new(), &v)
}

fn main() {
    let v = vec![A, A, B, AandB, B, A];
    assert_eq!(vec![A, AandB, AandB, B, A], combine(v));

    let v = vec![A, A, B, AandB, B, A, B, A, B];
    assert_eq!(vec![A, AandB, AandB, B, AandB, AandB], combine(v));

    let v = vec![A, A, B, AandB, B, A, B, A, A];
    assert_eq!(vec![A, AandB, AandB, B, AandB, A, A], combine(v));
}
使用事物::*; #[派生(复制、克隆、分区、调试)] 枚举对象{A,B,A和B} fn联合收割机(v:Vec)->Vec{ fn内部(mut res:Vec,s:&[Thing])->Vec{ 火柴{ [A,B,尾部..]=>{ res.push(AandB); 内部(res,tail) }, [a,尾巴..]=>{ res.push(a); 内部(res,tail) }, []=>res, } }; 内部(Vec::new(),&v) } fn main(){ 设v=vec![A,A,B,A和B,B,A]; assert_eq!(vec![A,AandB,AandB,B,A],combine(v)); 设v=vec![A,A,B,A,B,A,B,A,A,B]; 断言(vec![A,AandB,AandB,B,AandB,AandB],组合(v)); 设v=vec![A,A,B,A和B,B,A,B,A,A,A]; assert_eq!(vec![A,AandB,AandB,B,AandB,A,A],combine(v)); }
我合并了swizard的答案和Shepmaster的答案,最终得到了一个就地解决方案,该解决方案递归地运行于向量中,只有向量是可变的,任何东西都不会移动两次。不保证运行时或惯用性;)

使用事物::*; 使用std::cmp::min; #[派生(复制、克隆、分区、调试)] 枚举对象{A,B,A和B} fn联合收割机(mut v:Vec)->Vec{ fn内部(res:&mut Vec,i:usize,倒车档:usize){ 匹配&res[i..min(i+2,res.len())]{ [A,B]=>{ res[i-后移]=AandB; 内部(res,i+2,退档+1); }, [a,…]=>{ res[i-后移]=a; 内部(res,i+1,倒车档); }, []=>分辨率截断(i-后移), } }; 内部(&mutv,0,0); v } fn main(){ 设v=vec![A,A,B,A,B,A,B,A,A,B]; 断言(vec![A,AandB,AandB,B,AandB,AandB],组合(v)); 设v=vec![A,A,B,A和B,B,A,B,A,A,A]; assert_eq!(vec![A,AandB,AandB,B,AandB,A,A],combine(v)); }
好的,这是一个惯用的版本,没有显式for循环和递归:)

#[派生(部分查询、调试、复制)]
枚举对象{A,B,A和B}
fn联合收割机(mut v:Vec)->Vec{
let(_,total)=(0..v.len()).fold((无,0),|&mut:(上,下),i |{
设el=v[i];
让(下一个,项目)=匹配(el,上一个){
(Thing::B,Some(Thing::A))=>(end,Thing::A和B),
_=>(结束+1,el),
};
v[下一步-1]=项目;
(一些(el),下一个)
});
v、 截断(总);
v
}
fn main(){
让v=vec![Thing::A,Thing::A,Thing::B,Thing::A和B,Thing::B,Thing::A];
assert_eq!(vec![Thing::A,Thing::AandB,Thing::AandB,Thing::B,Thing::A],combine(v));
}

您还没有明确定义发生了什么;不在
A
s前面的
B
s会发生什么情况?那已经存在的a和b呢?另外,您希望转换在
Vec
中进行,还是正在分配新的转换?对不起!我只想将A和B组合起来。如果A和B已经存在,则应忽略它们。变换应该直接作用于向量!完成!感谢您在我的问题上投入了大量时间!非常感谢你!这肯定会起作用,而且速度很快,但无论如何它都不是惯用的生锈:p无论如何,谢谢!!给人印象深刻的这完全符合要求!非常感谢你!这是非常漂亮的防锈代码,谢谢!我真的很喜欢h
use Thing::*;

#[derive(Copy,Clone,PartialEq,Debug)]
enum Thing { A, B, AandB }

fn combine(v: Vec<Thing>) -> Vec<Thing> {
    fn inner(mut res: Vec<Thing>, s: &[Thing]) -> Vec<Thing> {
        match s {
            [A, B, tail..] => {
                res.push(AandB);
                inner(res, tail)
            },
            [a, tail..] => {
                res.push(a);
                inner(res, tail)
            },
            [] => res,
        }
    };

    inner(Vec::new(), &v)
}

fn main() {
    let v = vec![A, A, B, AandB, B, A];
    assert_eq!(vec![A, AandB, AandB, B, A], combine(v));

    let v = vec![A, A, B, AandB, B, A, B, A, B];
    assert_eq!(vec![A, AandB, AandB, B, AandB, AandB], combine(v));

    let v = vec![A, A, B, AandB, B, A, B, A, A];
    assert_eq!(vec![A, AandB, AandB, B, AandB, A, A], combine(v));
}
use Thing::*;
use std::cmp::min;

#[derive(Copy,Clone,PartialEq,Debug)]
enum Thing { A, B, AandB}

fn combine(mut v: Vec<Thing>) -> Vec<Thing> {
    fn inner(res: &mut Vec<Thing>, i: usize, backshift: usize) {
        match &res[i..min(i+2, res.len())] {
            [A, B] => {
                res[i - backshift] = AandB;
                inner(res, i + 2, backshift + 1);
            },
            [a, ..] => {
                res[i - backshift] = a;
                inner(res, i + 1, backshift);
            },
            [] => res.truncate(i - backshift),
        }
    };

    inner(&mut v, 0, 0);
    v
}

fn main() {
     let v = vec![A, A, B, AandB, B, A, B, A, B];
     assert_eq!(vec![A, AandB, AandB, B, AandB, AandB], combine(v));
     let v = vec![A, A, B, AandB, B, A, B, A, A];
     assert_eq!(vec![A, AandB, AandB, B, AandB, A, A], combine(v));
}
#[derive(PartialEq, Debug, Copy)]
enum Thing { A, B, AandB }
fn combine(mut v: Vec<Thing>) -> Vec<Thing> {
    let (_, total) = (0 .. v.len()).fold((None, 0), |&mut: (prev, end), i| {
        let el = v[i];
        let (next, item) = match (el, prev) {
            (Thing::B, Some(Thing::A)) => (end, Thing::AandB),
            _ => (end + 1, el),
        };
        v[next - 1] = item;
        (Some(el), next)
    });

    v.truncate(total);
    v
}

fn main() {
     let v = vec![Thing::A, Thing::A, Thing::B, Thing::AandB, Thing::B, Thing::A];
     assert_eq!(vec![Thing::A, Thing::AandB, Thing::AandB, Thing::B, Thing::A], combine(v));
}