连接字符串向量的向量 [英] Concatenate a vector of vectors of strings
问题描述
我正在尝试编写一个函数,该函数接收字符串向量的向量并返回所有串联在一起的向量,即它返回字符串向量。
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 $ c的方法$ c>很好,但是如果您不想再次克隆字符串,则必须在所有级别上使用
.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屋!