rust 有没有可能用迭代器把一个向量分成10个一组?

ljo96ir5  于 2023-03-30  发布在  其他
关注(0)|答案(4)|浏览(147)

我有let my_vec = (0..25).collect::<Vec<_>>(),我想把my_vec分成10个组的迭代器:

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
[10, 11, 12, 13, 14, 15, 16, 17, 18, 19];
[20, 21, 22, 23, 24, None, None, None, None, None];

Rust中的迭代器可以做到这一点吗?

bvn4nwqk

bvn4nwqk1#

Iterator trait上没有这样的helper方法。但是,有两种主要方法可以做到这一点:
1.使用**[T]::chunks()方法(可直接在Vec<T>上调用),但有一个细微的区别:它不会产生None,但最后一次迭代会产生一个更小的切片。对于总是精确的切片,如果它不完整,则忽略最后一个块,请参阅[T]::chunks_exact()**方法。
Example

let my_vec = (0..25).collect::<Vec<_>>();

    for chunk in my_vec.chunks(10) {
        println!("{:02?}", chunk);
    }

结果:

```none
[00, 01, 02, 03, 04, 05, 06, 07, 08, 09]
[10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
[20, 21, 22, 23, 24]

1.使用[the crate  `itertools`](https://crates.io/crates/itertools)中的**`Itertools::chunks()`**方法。这个crate扩展了标准库中的`Iterator` trait,所以这个`chunks()`方法适用于所有迭代器!注意,为了通用,用法稍微复杂一些。这与上面描述的方法具有相同的行为:在最后一次迭代中,块将更小,而不是包含`None` s。
[Example](https://play.rust-lang.org/?gist=de485e2ea81a861f649fe6fea5fbd89f&version=stable):

extern crate itertools;
use itertools::Itertools;

for chunk in &(0..25).chunks(10) {
    println!("{:02?}", chunk.collect::<Vec<_>>());
}

结果:
[00, 01, 02, 03, 04, 05, 06, 07, 08, 09]
[10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
[20, 21, 22, 23, 24]
sz81bmfz

sz81bmfz2#

您可以只使用标准库来实现与Lukas Kalbertodt's itertools example类似的解决方案:

let my_vec = (0..25).collect::<Vec<_>>();

let mut my_values = my_vec.into_iter().peekable();

while my_values.peek().is_some() {
    let chunk: Vec<_> = my_values.by_ref().take(10).collect();
    println!("{:?}", chunk);
}

结果:

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
[20, 21, 22, 23, 24]

如果实际上不需要每个块的Vec,可以省略collect调用,直接对by_ref创建的迭代器进行操作。
参见:

g2ieeal7

g2ieeal73#

我从Python中改编了一个技巧,以获得像Python的itertools提供的groupby()效果,即使用.zip().skip().step_by()合并两个或更多迭代器。这种方法可以产生10个组,但在代码库中看到它会非常不美观。但如果你需要小组,这可能是好的。
Rust确实有itertools板条箱,而.group_by()板条箱有itertools板条箱,但这并不总是可用的,这取决于具体情况--例如,向HackerRank这样的网站提交Rust解决方案。

fn main()
{
    let a = "Hello, World!";

    println!("{:?}", a.chars().step_by(2).zip(
                         a.chars().skip(1).step_by(2) 
                     ).collect::<Vec<_>>());
}

输出:

[('H', 'e'), ('l', 'l'), ('o', ','), (' ', 'W'), ('o', 'r'), ('l', 'd')]

其中n是压缩迭代器的数量,对于所有迭代器,.step_by的值将是n,而.skip()的值将取决于迭代器在链中的位置;第一个迭代器将跳过0、下一个1等。
你可以用这种方式链接任何数量的迭代器,但是在第三个之后,它开始看起来有点复杂和丑陋。在这种情况下,也许可以考虑将迭代器收集到Vec中并使用它的.chunks()方法。或者如果可以的话,使用itertools crate。

q1qsirdb

q1qsirdb4#

使用或不使用人造丝分块一个矢量。
然后将一些功能Map到每个部分。
在下面的示例中,使用了sum函数。

use rayon::prelude::*;

fn main() {
    let my_vec: Vec<_> = (0..25).collect();
    let chunk_size = 10;

    let chunks_without_rayon: Vec<_> = my_vec
        .chunks(chunk_size)
        .enumerate()
        .map(|(i, chunk)| {
            println!("chunk{i}: {chunk:?}");
            chunk.iter().sum::<i32>()
        })
        .collect();

    println!("chunks_without_rayon = {chunks_without_rayon:?}\n");

    let chunks_with_rayon: Vec<_> = my_vec
        .par_chunks(chunk_size)
        .enumerate()
        .map(|(i, chunk)| {
            println!("chunk{i}: {chunk:?}");
            chunk.iter().sum::<i32>()
        })
        .collect();

    println!("chunks_with_rayon: {chunks_with_rayon:?}")
}

输出:

chunk0: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
chunk1: [10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
chunk2: [20, 21, 22, 23, 24]
chunks_without_rayon = [45, 145, 110]

chunk0: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
chunk1: [10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
chunk2: [20, 21, 22, 23, 24]
chunks_with_rayon: [45, 145, 110]

相关问题