连接字符串向量的向量 [英] Concatenate a vector of vectors of strings

查看:129
本文介绍了连接字符串向量的向量的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试编写一个函数,该函数接收字符串向量的向量并返回所有串联在一起的向量,即它返回字符串向量。

I'm trying to write a function that receives a vector of vectors of strings and returns all vectors concatenated together, i.e. it returns a vector of strings.

到目前为止,我能做的最好的事情是:

The best I could do so far has been the following:

fn concat_vecs(vecs: Vec<Vec<String>>) -> Vec<String> {
    let vals : Vec<&String> = vecs.iter().flat_map(|x| x.into_iter()).collect();
    vals.into_iter().map(|v: &String| v.to_owned()).collect()
}

但是,我对这个结果并不满意,因为看来我应该能够得到 Vec< String> 从第一个 collect 调用开始,但是不知为何我无法弄清楚该怎么做。

However, I'm not happy with this result, because it seems I should be able to get Vec<String> from the first collect call, but somehow I am not able to figure out how to do it.

我是甚至更想找出为什么 collect 的返回类型是 Vec<& String> 。我试图从API文档和源代码中推断出这一点,但是尽管我做了最大的努力,但我什至无法理解函数的签名。

I am even more interested to figure out why exactly the return type of collect is Vec<&String>. I tried to deduce this from the API documentation and the source code, but despite my best efforts, I couldn't even understand the signatures of functions.

所以让我尝试一下并跟踪每个表达式的类型:

So let me try and trace the types of each expression:

- vecs.iter(): Iter<T=Vec<String>, Item=Vec<String>>
- vecs.iter().flat_map(): FlatMap<I=Iter<Vec<String>>, U=???, F=FnMut(Vec<String>) -> U, Item=U>
- vecs.iter().flat_map().collect(): (B=??? : FromIterator<U>)
- vals was declared as Vec<&String>, therefore 
      vals == vecs.iter().flat_map().collect(): (B=Vec<&String> : FromIterator<U>). Therefore U=&String.

我在上面假设类型推断器能够弄清楚 U =& String 基于 vals 的类型。但是,如果我在代码中为表达式指定了显式类型,则编译时不会出错:

I'm assuming above that the type inferencer is able to figure out that U=&String based on the type of vals. But if I give the expression the explicit types in the code, this compiles without error:

fn concat_vecs(vecs: Vec<Vec<String>>) -> Vec<String> {
    let a: Iter<Vec<String>> = vecs.iter();
    let b: FlatMap<Iter<Vec<String>>, Iter<String>, _> = a.flat_map(|x| x.into_iter());
    let c = b.collect();
    print_type_of(&c);
    let vals : Vec<&String> = c;
    vals.into_iter().map(|v: &String| v.to_owned()).collect()
}

很显然, U = Iter< String> ...请帮助我清除此混乱情况。

Clearly, U=Iter<String>... Please help me clear up this mess.

编辑::由于bluss的提示,我得以实现一个 collect ,如下所示:

thanks to bluss' hint, I was able to achieve one collect as follows:

fn concat_vecs(vecs: Vec<Vec<String>>) -> Vec<String> {
    vecs.into_iter().flat_map(|x| x.into_iter()).collect()
}

我的理解是,通过使用 into_iter 我将 vecs 的所有权转让给 IntoIter 并进一步扩展到调用链,这使我避免了在lambda调用内复制数据,因此-神奇的是,类型系统为我提供了 Vec< String> 以前曾经总是给我 Vec<& String> 。看到高级概念如何在图书馆的工作中体现当然很酷,但我希望我对如何实现这一想法有所了解。

My understanding is that by using into_iter I transfer ownership of vecs to IntoIter and further down the call chain, which allows me to avoid copying the data inside the lambda call and therefore - magically - the type system gives me Vec<String> where it used to always give me Vec<&String> before. While it is certainly very cool to see how the high-level concept is reflected in the workings of the library, I wish I had any idea how this is achieved.

编辑2:经过费力的猜测之后,查看API文档并使用此方法进行解密的类型,我得到了完全注释(不考虑生命周期):

EDIT 2: After a laborious process of guesswork, looking at API docs and using this method to decipher the types, I got them fully annotated (disregarding the lifetimes):

fn concat_vecs(vecs: Vec<Vec<String>>) -> Vec<String> {
    let a: Iter<Vec<String>> = vecs.iter();
    let f : &Fn(&Vec<String>) -> Iter<String> = &|x: &Vec<String>| x.into_iter();
    let b: FlatMap<Iter<Vec<String>>, Iter<String>, &Fn(&Vec<String>) -> Iter<String>> = a.flat_map(f);
    let vals : Vec<&String> = b.collect();
    vals.into_iter().map(|v: &String| v.to_owned()).collect()
}


推荐答案

我会考虑:为什么在外层vec上使用iter()但在内层vec上使用into_iter()?实际上,使用 into_iter()至关重要,因此我们不必先复制内部向量,然后再复制内部的字符串,我们只需获得它们的所有权即可。

I'd think about: why do you use iter() on the outer vec but into_iter() on the inner vecs? Using into_iter() is actually crucial, so that we don't have to copy first the inner vectors, then the strings inside, we just receive ownership of them.

我们实际上可以像求和一样写:将向量两两相连。由于我们总是重复使用分配和

We can actually write this just like a summation: concatenate the vectors two by two. Since we always reuse the allocation & contents of the same accumulation vector, this operation is linear time.

为了最小化增长和重新分配矢量所花费的时间,请计算前端所需的空间。

To minimize time spent growing and reallocating the vector, calculate the space needed up front.

fn concat_vecs(vecs: Vec<Vec<String>>) -> Vec<String> {
    let size = vecs.iter().fold(0, |a, b| a + b.len());
    vecs.into_iter().fold(Vec::with_capacity(size), |mut acc, v| {
        acc.extend(v); acc
    })
}

如果您确实想克隆所有内容,则已经有一种方法可以使用,只需使用 vecs.concat()/ *-> Vec< String> * /

If you do want to clone all the contents, there's already a method for that, and you'd just use vecs.concat() /* -> Vec<String> */

使用 .flat_map 很好,但是如果您不想再次克隆字符串,则必须在所有级别上使用 .into_iter():( x Vec< String> )。

The approach with .flat_map is fine, but if you don't want to clone the strings again you have to use .into_iter() on all levels: (x is Vec<String>).

vecs .into_iter()。flat_map(| x | x.into_iter())。collect()

如果您想克隆每个字符串您可以使用此方法:(将 .into_iter()更改为 .iter(),因为 x 这是一个& Vec< String> ,这两种方法实际上都导致相同的结果!)

If instead you want to clone each string you can use this: (Changed .into_iter() to .iter() since x here is a &Vec<String> and both methods actually result in the same thing!)

vecs.iter()。flat_map(| x | x.iter()。map(Clone :: clone))。collect()

这篇关于连接字符串向量的向量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆