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>()
    );
}