Coding style 如何将Vec部分折叠到位?
我想浏览一个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::
#[派生(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));
}