Recursion 如何使用递归迭代器展平递归结构?
我正试图扁平化递归结构,但递归迭代器有问题 下面是结构的外观:Recursion 如何使用递归迭代器展平递归结构?,recursion,rust,flatten,Recursion,Rust,Flatten,我正试图扁平化递归结构,但递归迭代器有问题 下面是结构的外观: #[derive(Debug, Clone)] pub struct C { name: String, vb: Option<Vec<B>>, } #[derive(Debug, Clone)] pub struct B { c: Option<C>, } #[derive(Debug, Clone)] pub struct A { vb: Option<
#[derive(Debug, Clone)]
pub struct C {
name: String,
vb: Option<Vec<B>>,
}
#[derive(Debug, Clone)]
pub struct B {
c: Option<C>,
}
#[derive(Debug, Clone)]
pub struct A {
vb: Option<Vec<B>>,
flat_c: Option<Vec<C>>,
}
这里是我设法做到的,在某种程度上扁平化了结构,但只针对最后一个元素,因为没有实现递归
impl A {
fn flat_c(self) -> Self {
let fc: Vec<C> = self
.vb
.clone()
.unwrap()
.iter()
.flat_map(|x| x.c.as_ref().unwrap().vb.as_ref().unwrap().iter())
.cloned()
.map(|x| x.c.unwrap())
.collect();
Self {
flat_c: Some(fc),
..self
}
}
}
fn main() {
let a = A {
vb: Some(vec![
B {
c: Some(C {
name: "foo".to_string(),
vb: Some(vec![B {
c: Some(C {
name: "bar".to_string(),
vb: None,
}),
}]),
}),
},
B {
c: Some(C {
name: "fiz".to_string(),
vb: Some(vec![B {
c: Some(C {
name: "buzz".to_string(),
vb: None,
}),
}]),
}),
},
]),
flat_c: None,
};
let a = a.flat_c();
println!("a: {:#?}", a);
}
我还没有深入讨论这个问题可能需要的迭代器
特性实现
我将如何解决这个问题?可能使用
折叠
?也许甚至不需要递归方法?我不知所措。我不确定您希望“遍历vb
向量并将其展平为flat_c
”的结果是什么,但下面是一个稍微简单的展平递归结构的示例,用于对应于当前节点的值,要将其与其子级连接并展平所有内容:
use std::iter::once;
#[derive(Debug)]
struct S {
name: String,
children: Vec<S>,
}
impl S {
fn flat(self) -> Vec<String> {
once(self.name)
.chain(self.children.into_iter().flat_map(|c| c.flat()))
.collect()
}
}
fn main() {
let s = S {
name: "parent".into(),
children: vec![
S {
name: "child 1".into(),
children: vec![],
},
S {
name: "child 2".into(),
children: vec![],
},
],
};
println!("s: {:?}", s);
println!("flat: {:?}", s.flat());
}
使用std::iter::一次;
#[导出(调试)]
结构{
名称:String,
儿童:Vec,
}
impl S{
fn平面(自)->Vec{
一次(self.name)
.chain(self.children.into_iter().flat_map(| c | c.flat()))
.collect()
}
}
fn main(){
设s=s{
名称:“parent.into(),
孩子们:vec[
{
名称:“child 1.into(),
儿童:vec![],
},
{
名称:“child 2.into(),
儿童:vec![],
},
],
};
println!((“s:{:?}”,s);
println!(“flat:{:?}”,s.flat());
}
我的解决方案是:
impl C {
fn flat(&self) -> Vec<C> {
let mut result = Vec::new();
result.push(C {
name: self.name.clone(),
vb: None,
});
if self.vb.is_some() {
result.extend(
(self.vb.as_ref().unwrap().iter())
.flat_map(|b| b.c.as_ref().map(|c| c.flat()).unwrap_or(Vec::new())),
);
}
return result;
}
}
impl A {
fn flat_c(self) -> Self {
let fc = (self.vb.as_ref().unwrap().iter())
.flat_map(|b| b.c.as_ref().unwrap().flat())
.collect();
Self {
flat_c: Some(fc),
..self
}
}
}
impl C{
fn平坦(和自)->Vec{
让mut result=Vec::new();
结果:推(C){
名称:self.name.clone(),
vb:没有,
});
如果self.vb.is_some(){
result.extend(
(self.vb.as_ref().unwrap().iter())
.flat_map(| b | b.c.as_ref()。map(| c | c.flat())。展开或(Vec::new()),
);
}
返回结果;
}
}
暗示{
fn平面(自)->自{
设fc=(self.vb.as_ref().unwrap().iter())
.展开图(| b | b.c.作为|参考().展开().展开())
.收集();
自我{
平面c:一些(fc),
自己
}
}
}
它为C
添加了flat
函数,因为C
是递归的源,只有此结构可以正确处理它
由于这些选项
s,它看起来很可怕,而且很难处理隐藏的错误消息。此解决方案假定初始a
的所有b.c
s不是None
。否则,它就会惊慌失措。我的建议是避免使用选项
,只使用空向量而不是None
熟悉常用数据结构是个好主意。你有一个选择,有几种方法。您没有明确指定要使用哪种方法,所以我随意选择了一种易于实现的方法 这里的关键是实现一个迭代器来跟踪某些状态:所有待访问的节点。在每次调用
迭代器::next
时,我们取下一个值,将要访问的任何新节点保存在一边,然后返回该值
拥有迭代器后,您可以将其收集到Vec
中
use std::collections::VecDeque;
impl IntoIterator for A {
type IntoIter = IntoIter;
type Item = String;
fn into_iter(self) -> Self::IntoIter {
IntoIter {
remaining: self.vb.into_iter().flatten().collect(),
}
}
}
struct IntoIter {
remaining: VecDeque<B>,
}
impl Iterator for IntoIter {
type Item = String;
fn next(&mut self) -> Option<Self::Item> {
self.remaining.pop_front().and_then(|b| {
b.c.map(|C { name, vb }| {
self.remaining.extend(vb.into_iter().flatten());
name
})
})
}
}
fn to_strings(a: A) -> Vec<String> {
a.into_iter().collect()
}
#[derive(Debug, Clone)]
struct A {
vb: Option<Vec<B>>,
}
#[derive(Debug, Clone)]
struct B {
c: Option<C>,
}
#[derive(Debug, Clone)]
struct C {
name: String,
vb: Option<Vec<B>>,
}
fn main() {
let example: A = A {
vb: Some(vec![
B {
c: Some(C {
name: "Hello ".to_string(),
vb: None,
}),
},
B {
c: Some(C {
name: "World!".to_string(),
vb: None,
}),
},
]),
};
println!("The example struct: {:?}", example);
//clone a copy for a second example, because to_strings() takes ownership of the example A struct
let receipt: A = example.clone();
println!("Iterated: {:?}", to_strings(example));
// another example of using to_strings()
println!(
"As a string: {:?}",
to_strings(receipt).into_iter().collect::<String>()
);
}
使用std::collections::VecDeque;
一个函数的impl-into迭代器{
输入iter=输入iter;
类型项=字符串;
fn进入iter(self)->self::进入iter{
输入者{
剩余:self.vb.into_iter().flatte().collect(),
}
}
}
结构输入器{
剩余:维德克,
}
IntoIter的impl迭代器{
类型项=字符串;
fn下一步(&mut self)->选项{
self.remaining.pop_front()和_then(|b|{
b、 c.map(|c{name,vb}|{
self.remaining.extend(vb.into_iter().flatte());
名称
})
})
}
}
fn到_字符串(a:a)->Vec{
a、 放入iter().collect()中
}
#[派生(调试、克隆)]
结构A{
vb:选项,
}
#[派生(调试、克隆)]
结构B{
c:选项,
}
#[派生(调试、克隆)]
结构C{
名称:String,
vb:选项,
}
fn main(){
举个例子:A=A{
vb:一些(vec[
B{
c:一些{
名称:“Hello”。to_string(),
vb:没有,
}),
},
B{
c:一些{
名称:“世界!”。至_string(),
vb:没有,
}),
},
]),
};
println!(“示例结构:{:?}”,示例);
//克隆第二个示例的副本,因为to_strings()拥有示例结构的所有权
let receive:A=example.clone();
println!(“迭代:{:?}”,to_字符串(示例));
//使用to_strings()的另一个示例
普林顿(
“作为字符串:{:?}”,
to_字符串(收据)。to_iter()。collect::()
);
}
从这里开始,如果您需要的话,应该直接创建B
的迭代器。让所有的None
值看起来都很愚蠢,所以我将它们省略,直接返回String
s
我还将其作为一个按值迭代器。您可以按照相同的模式创建一个迭代器,该迭代器返回对B
/字符串的引用,并仅根据需要克隆它们
另见:
有了发电机,这将很容易,但我不知道如何优雅地完成……谢谢,看起来这正是我想要的。只要我对你的解决方案稍加研究,我就会验证你的答案。我最终选择了Shepmaster的解决方案,因为我发现迭代器impl更灵活,你的答案也更有效。谢谢,我觉得我需要实现一些特性,使它更优雅。非常感谢您提供的大量资源。这是一个将
impl C {
fn flat(&self) -> Vec<C> {
let mut result = Vec::new();
result.push(C {
name: self.name.clone(),
vb: None,
});
if self.vb.is_some() {
result.extend(
(self.vb.as_ref().unwrap().iter())
.flat_map(|b| b.c.as_ref().map(|c| c.flat()).unwrap_or(Vec::new())),
);
}
return result;
}
}
impl A {
fn flat_c(self) -> Self {
let fc = (self.vb.as_ref().unwrap().iter())
.flat_map(|b| b.c.as_ref().unwrap().flat())
.collect();
Self {
flat_c: Some(fc),
..self
}
}
}
use std::collections::VecDeque;
impl IntoIterator for A {
type IntoIter = IntoIter;
type Item = String;
fn into_iter(self) -> Self::IntoIter {
IntoIter {
remaining: self.vb.into_iter().flatten().collect(),
}
}
}
struct IntoIter {
remaining: VecDeque<B>,
}
impl Iterator for IntoIter {
type Item = String;
fn next(&mut self) -> Option<Self::Item> {
self.remaining.pop_front().and_then(|b| {
b.c.map(|C { name, vb }| {
self.remaining.extend(vb.into_iter().flatten());
name
})
})
}
}
fn to_strings(a: A) -> Vec<String> {
a.into_iter().collect()
}
#[derive(Debug, Clone)]
struct A {
vb: Option<Vec<B>>,
}
#[derive(Debug, Clone)]
struct B {
c: Option<C>,
}
#[derive(Debug, Clone)]
struct C {
name: String,
vb: Option<Vec<B>>,
}
fn main() {
let example: A = A {
vb: Some(vec![
B {
c: Some(C {
name: "Hello ".to_string(),
vb: None,
}),
},
B {
c: Some(C {
name: "World!".to_string(),
vb: None,
}),
},
]),
};
println!("The example struct: {:?}", example);
//clone a copy for a second example, because to_strings() takes ownership of the example A struct
let receipt: A = example.clone();
println!("Iterated: {:?}", to_strings(example));
// another example of using to_strings()
println!(
"As a string: {:?}",
to_strings(receipt).into_iter().collect::<String>()
);
}