将结构体的迭代器解包为字段的迭代器

huangapple go评论73阅读模式
英文:

Rust unpack iter of structs to iter of fields

问题

let (iter_a, (iter_b, iter_c)): (
    Box<dyn Iterator<Item = &i32>>,
    (Box<dyn Iterator<Item = &f64>>, Box<dyn Iterator<Item = &String>>),
) = bar.iter().map(|elem| (&elem.a, (&elem.b, &elem.c)));
英文:

Assume I have a struct like this

struct Foo {
    a: i32,
    b: f64,
    c: String,
    d: u8,
}

And bar is of type Vec&lt;Foo&gt;, which already contains many elements.

I would like to have three iterators of Foo's first three fields (a, b and c) respectively. I know how to use unzip to achieve unpacking bar to its fields .

let (vec_a, (vec_b, vec_c)): (Vec&lt;i32&gt;, (Vec&lt;f64&gt;, Vec&lt;String&gt;)) = bar
    .iter()
    .map(|elem| (elem.a, (elem.b, elem.c)))
    .unzip();

But I don't know how to make iterators in ways alike.

let (iter_a, (iter_b, iter_c)): (
    Box&lt;dyn Iterator&lt;Item = i32&gt;&gt;,
    (Box&lt;dyn Iterator&lt;Item = f64&gt;&gt;, Box&lt;dyn Iterator&lt;Item = String&gt;&gt;),
) = bar.iter().map(|elem| (elem.a, (elem.b, elem.c)));

This results in error[E0308]: mismatched types. Did I miss something or I just cannot use the syntax above at all.

Also as another question, unzip can only unzip pairs, if the struct has many fields, the nested level will soon explode, is there any better way to achieve my goal?

答案1

得分: 0

> Did I miss something or I just cannot use the syntax above at all.

我有遗漏什么吗,还是说我根本不能使用上面的语法。

The snippet just doesn't make any sense, map is a single iterator not 3, and it furthermore is not boxed.

这段代码完全没有意义,map 只是一个单一的迭代器,而不是3个,并且它还没有被包装。

> Also as another question, unzip can only unzip pairs, if the struct has many fields, the nested level will soon explode, is there any better way to achieve my goal?

另外一个问题是,解压只能解压成对的数据,如果结构体有很多字段,嵌套层级很快就会爆炸,有没有更好的方法来实现我的目标?

https://docs.rs/itertools/latest/itertools/fn.multiunzip.html 应该适用于多达12个元组。

英文:

> Did I miss something or I just cannot use the syntax above at all.

The snippet just doesn't make any sense, map is a single iterator not 3, and it furthermore is not boxed.

> Also as another question, unzip can only unzip pairs, if the struct has many fields, the nested level will soon explode, is there any better way to achieve my goal?

https://docs.rs/itertools/latest/itertools/fn.multiunzip.html should work for up to 12-uples.

答案2

得分: 0

以下是您提供的内容的翻译:

我只会制作三个不同的迭代器。

在下面的示例中,第一部分使用了.unzip(),但修复了一些错误。
.iter() 阻止了对 elem.c 的消耗。
如果我们不想使用 .into_iter(),我们需要要么一个引用(.as_str()),要么一个克隆(.clone())。

第二部分只是制作了三个不同的迭代器。
这是我更喜欢的解决方案,正如第一句所述。

第三部分尝试保留您的原始想法:从一个迭代器开始,并期望将其分割为三个部分。
如果获取初始迭代器的过程非常复杂且我们不想重复三次,那么这可能有道理。
在这种情况下,我们必须克隆初始迭代器本身,并为每个迭代器添加最终的 .map() 阶段。

struct Foo {
    a: i32,
    b: f64,
    c: String,
    _d: u8,
}

fn show_iter<I, E>(
    title: &str,
    iter: I,
) where
    I: Iterator<Item = E>,
    E: std::fmt::Debug,
{
    print!("{}:", title);
    for e in iter {
        print!(" {:?}", e);
    }
    println!();
}

fn main() {
    let bar = vec![
        Foo {
            a: 1,
            b: 2.3,
            c: "X".to_owned(),
            _d: 4,
        },
        Foo {
            a: 2,
            b: 3.4,
            c: "Y".to_owned(),
            _d: 5,
        },
        Foo {
            a: 3,
            b: 4.5,
            c: "Z".to_owned(),
            _d: 6,
        },
    ];
    {
        // 或者使用 vec_c: Vec<String> 和 elem.c.clone()
        let (vec_a, (vec_b, vec_c)): (Vec<i32>, (Vec<f64>, Vec<&str>)) = bar
            .iter()
            .map(|elem| (elem.a, (elem.b, elem.c.as_str())))
            .unzip();
        println!("vec_a: {:?}", vec_a);
        println!("vec_b: {:?}", vec_b);
        println!("vec_c: {:?}", vec_c);
    }
    println!("~~~~~~~~~~~~~~~~");
    {
        let iter_a = bar.iter().map(|elem| elem.a);
        let iter_b = bar.iter().map(|elem| elem.b);
        // 或者使用 elem.c.clone()
        let iter_c = bar.iter().map(|elem| elem.c.as_str());
        show_iter("iter_a", iter_a);
        show_iter("iter_b", iter_b);
        show_iter("iter_c", iter_c);
    }
    println!("~~~~~~~~~~~~~~~~");
    {
        // 或者使用 elem.c.clone()
        let iter_abc =
            bar.iter().map(|elem| (elem.a, elem.b, elem.c.as_str()));
        let iter_a = iter_abc.clone().map(|(a, _b, _c)| a);
        let iter_b = iter_abc.clone().map(|(_a, b, _c)| b);
        let iter_c = iter_abc.map(|(_a, _b, c)| c);
        show_iter("iter_abc iter_a", iter_a);
        show_iter("iter_abc iter_b", iter_b);
        show_iter("iter_abc iter_c", iter_c);
    }
}
/*
vec_a: [1, 2, 3]
vec_b: [2.3, 3.4, 4.5]
vec_c: ["X", "Y", "Z"]
~~~~~~~~~~~~~~~~
iter_a: 1 2 3
iter_b: 2.3 3.4 4.5
iter_c: "X" "Y" "Z"
~~~~~~~~~~~~~~~~
iter_abc iter_a: 1 2 3
iter_abc iter_b: 2.3 3.4 4.5
iter_abc iter_c: "X" "Y" "Z"
*/
英文:

I would simply make three distinct iterators.

In the example below, the first part uses .unzip() as you did but fixes some errors.
.iter() prevents from consuming elem.c.
If we do not want to use .into_iter(), we need either a reference (.as_str()) or a clone (.clone()).

The second part simply makes three distinct iterators.
It's the solution I prefer, as stated in the first sentence.

The third part tries to keep your original idea: start from one iterator and expect to split it in three.
It could make sense if the process of obtaining the initial iterator was quite complicated and we didn't want to repeat it three times.
In this case, we have to clone the initial iterator itself and add a final .map() stage to each one.

struct Foo {
    a: i32,
    b: f64,
    c: String,
    _d: u8,
}

fn show_iter&lt;I, E&gt;(
    title: &amp;str,
    iter: I,
) where
    I: Iterator&lt;Item = E&gt;,
    E: std::fmt::Debug,
{
    print!(&quot;{}:&quot;, title);
    for e in iter {
        print!(&quot; {:?}&quot;, e);
    }
    println!();
}

fn main() {
    let bar = vec![
        Foo {
            a: 1,
            b: 2.3,
            c: &quot;X&quot;.to_owned(),
            _d: 4,
        },
        Foo {
            a: 2,
            b: 3.4,
            c: &quot;Y&quot;.to_owned(),
            _d: 5,
        },
        Foo {
            a: 3,
            b: 4.5,
            c: &quot;Z&quot;.to_owned(),
            _d: 6,
        },
    ];
    {
        // or use   vec_c: Vec&lt;String&gt;   and   elem.c.clone()
        let (vec_a, (vec_b, vec_c)): (Vec&lt;i32&gt;, (Vec&lt;f64&gt;, Vec&lt;&amp;str&gt;)) = bar
            .iter()
            .map(|elem| (elem.a, (elem.b, elem.c.as_str())))
            .unzip();
        println!(&quot;vec_a: {:?}&quot;, vec_a);
        println!(&quot;vec_b: {:?}&quot;, vec_b);
        println!(&quot;vec_c: {:?}&quot;, vec_c);
    }
    println!(&quot;~~~~~~~~~~~~~~~~&quot;);
    {
        let iter_a = bar.iter().map(|elem| elem.a);
        let iter_b = bar.iter().map(|elem| elem.b);
        // or use   elem.c.clone()
        let iter_c = bar.iter().map(|elem| elem.c.as_str());
        show_iter(&quot;iter_a&quot;, iter_a);
        show_iter(&quot;iter_b&quot;, iter_b);
        show_iter(&quot;iter_c&quot;, iter_c);
    }
    println!(&quot;~~~~~~~~~~~~~~~~&quot;);
    {
        // or use   elem.c.clone()
        let iter_abc =
            bar.iter().map(|elem| (elem.a, elem.b, elem.c.as_str()));
        let iter_a = iter_abc.clone().map(|(a, _b, _c)| a);
        let iter_b = iter_abc.clone().map(|(_a, b, _c)| b);
        let iter_c = iter_abc.map(|(_a, _b, c)| c);
        show_iter(&quot;iter_abc iter_a&quot;, iter_a);
        show_iter(&quot;iter_abc iter_b&quot;, iter_b);
        show_iter(&quot;iter_abc iter_c&quot;, iter_c);
    }
}
/*
vec_a: [1, 2, 3]
vec_b: [2.3, 3.4, 4.5]
vec_c: [&quot;X&quot;, &quot;Y&quot;, &quot;Z&quot;]
~~~~~~~~~~~~~~~~
iter_a: 1 2 3
iter_b: 2.3 3.4 4.5
iter_c: &quot;X&quot; &quot;Y&quot; &quot;Z&quot;
~~~~~~~~~~~~~~~~
iter_abc iter_a: 1 2 3
iter_abc iter_b: 2.3 3.4 4.5
iter_abc iter_c: &quot;X&quot; &quot;Y&quot; &quot;Z&quot;
*/

huangapple
  • 本文由 发表于 2023年6月8日 15:05:17
  • 转载请务必保留本文链接:https://go.coder-hub.com/76429366.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定