首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >哪种方式更好地将vec<&String>转换为vec<String>

哪种方式更好地将vec<&String>转换为vec<String>
EN

Stack Overflow用户
提问于 2021-09-23 15:58:42
回答 1查看 280关注 0票数 0

基本上,我有一个函数来过滤所有长度最长的字符串。为了避免错误expected struct 'String', found '&String',我尝试了以下两种解决方案。他们都给出了正确的结果。

into_iter

代码语言:javascript
复制
fn allLongestStrings(inputArray: Vec<String>) -> Vec<String> {
    let max_len = inputArray.iter().map(|string| string.len()).max().unwrap();
    inputArray.into_iter().filter(|string| string.len().eq(&max_len)).collect()
}

iter

代码语言:javascript
复制
fn allLongestStrings(inputArray: Vec<String>) -> Vec<String> {
    let max_len = inputArray.iter().map(|string| string.len()).max().unwrap();
    inputArray.iter().filter(|string| string.len().eq(&max_len)).map(|s| s.to_string()).collect()
}

into_iter看起来更干净,但是在这个回答中,它说into_iter的结果有时令人惊讶。

  1. 那么,我应该选择上述哪种方法呢?
  2. 还有,速度有什么不同吗?
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-09-23 21:32:19

假设这两种方法都以值表示向量,那么第一个版本(使用into_iter())会更好,因为它不会复制字符串。

当一个字符串与条件匹配时,它将被移动到目标向量中。使用第二个版本(使用iter())时,当字符串与谓词匹配时,将复制该字符串,并将副本移动到目标vector.This中,从而产生更多的分配和更多的释放。

下面是简单的标准基准测试,以证明:

代码语言:javascript
复制
use criterion::{black_box, criterion_group, criterion_main, BenchmarkId, Criterion}; //0.3.5

criterion_group!(benches, benchmark);
criterion_main!(benches);

pub fn benchmark(c: &mut Criterion) {
    let input = vec![
        "some string".to_owned(),
        "some string".to_owned(),
        "some string".to_owned(),
        "some string".to_owned(),
        "some string".to_owned(),
        "some string".to_owned(),
        "some string".to_owned(),
    ];

    c.bench_with_input(BenchmarkId::new("with_iter", ""), &input, |b, i| {
        b.iter(|| {
            let result = with_iter(i.clone());
            black_box(result);
        });
    });

    c.bench_with_input(BenchmarkId::new("with_into_iter", ""), &input, |b, i| {
        b.iter(|| {
            let result = with_into_iter(i.clone());
            black_box(result);
        });
    });
}

fn with_into_iter(input_array: Vec<String>) -> Vec<String> {
    let max_len = input_array.iter().map(|string| string.len()).max().unwrap();
    input_array
        .into_iter()
        .filter(|string| string.len() == max_len)
        .collect()
}

fn with_iter(input_array: Vec<String>) -> Vec<String> {
    let max_len = input_array.iter().map(|string| string.len()).max().unwrap();
    input_array
        .iter()
        .filter(|string| string.len() == max_len)
        .map(|s| s.to_string())
        .collect()
}

这显然是复制所有值的极端情况。根据您的输入,如果要复制的短字符串很少,则差异可能可以忽略不计。

代码语言:javascript
复制
with_iter/              time:   [392.30 ns 394.80 ns 397.93 ns]                       
with_into_iter/         time:   [153.07 ns 153.41 ns 153.79 ns]                            

显然,时间取决于要复制的字符串的数量及其长度,因此实际的时间取决于函数的输入。

PS:如果你想尽可能快,你可以使用retain()

代码语言:javascript
复制
fn with_retain(mut input_array: Vec<String>) -> Vec<String> {
    let max_len = input_array.iter().map(|string| string.len()).max().unwrap();
    input_array.retain(|string| string.len() == max_len);
    input_array
}
代码语言:javascript
复制
with_retain/      time:   [143.98 ns 144.22 ns 144.50 ns]                               

它更快,因为:

  • 它不分配第二个“结果”向量。
  • 如果有大量匹配,则不需要调整结果向量的大小(因为输出长度总是<=输入长度),从而避免了额外的分配/释放&复制。

缺点是,如果长输入数组上的匹配非常少,那么输出向量就会太大,从而浪费一些内存。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/69303336

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档