连接字符串向量的向量
Concatenate a vector of vectors of strings
我正在尝试编写一个函数,该函数接收字符串向量的向量和 return 连接在一起的所有向量,即它 return 是一个字符串向量。
到目前为止我能做的最好的是:
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()
}
但是,我对这个结果并不满意,因为看起来我应该能够从第一个 collect
调用中获得 Vec<String>
,但不知何故我无法弄清楚如何去做。
我更想弄清楚为什么 collect
的return 类型是Vec<&String>
。我试图从 API 文档和源代码中推断出这一点,但尽管我尽了最大努力,我什至无法理解函数的签名。
所以让我试着追踪每个表达式的类型:
- 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.
我在上面假设类型推断器能够根据 vals
的类型计算出 U=&String
。但是,如果我在代码中为表达式提供显式类型,则编译时不会出现错误:
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>
...请帮我清理一下这个烂摊子。
编辑: 感谢 bluss 的提示,我能够实现一个 collect
如下:
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>
的地方。虽然看到高级概念如何反映在库的工作中当然非常酷,但我希望我知道这是如何实现的。
编辑 2: 经过艰苦的猜测过程,查看 API 文档并使用 this method 来破译类型,我得到了完整的注释(忽略生命周期):
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()
实际上是至关重要的,这样我们就不必先复制内部向量,然后再复制内部的字符串,我们只需要获得它们的所有权即可。
我们实际上可以像求和一样写这个:将向量两两连接起来。由于我们总是重复使用同一个累加向量的分配和内容,所以这个操作是线性时间的。
为了尽量减少增长和重新分配矢量所花费的时间,请预先计算 space 所需的数量。
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> */
.flat_map
的方法很好,但是如果您不想再次克隆字符串,则必须在所有级别上使用 .into_iter()
:(x
是 Vec<String>
).
vecs.into_iter().flat_map(|x| x.into_iter()).collect()
如果你想克隆每个字符串,你可以使用这个:(将 .into_iter()
更改为 .iter()
因为 x
这里是一个 &Vec<String>
并且这两种方法实际上都会产生同样的事情!)
vecs.iter().flat_map(|x| x.iter().map(Clone::clone)).collect()
我正在尝试编写一个函数,该函数接收字符串向量的向量和 return 连接在一起的所有向量,即它 return 是一个字符串向量。
到目前为止我能做的最好的是:
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()
}
但是,我对这个结果并不满意,因为看起来我应该能够从第一个 collect
调用中获得 Vec<String>
,但不知何故我无法弄清楚如何去做。
我更想弄清楚为什么 collect
的return 类型是Vec<&String>
。我试图从 API 文档和源代码中推断出这一点,但尽管我尽了最大努力,我什至无法理解函数的签名。
所以让我试着追踪每个表达式的类型:
- 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.
我在上面假设类型推断器能够根据 vals
的类型计算出 U=&String
。但是,如果我在代码中为表达式提供显式类型,则编译时不会出现错误:
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>
...请帮我清理一下这个烂摊子。
编辑: 感谢 bluss 的提示,我能够实现一个 collect
如下:
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>
的地方。虽然看到高级概念如何反映在库的工作中当然非常酷,但我希望我知道这是如何实现的。
编辑 2: 经过艰苦的猜测过程,查看 API 文档并使用 this method 来破译类型,我得到了完整的注释(忽略生命周期):
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()
实际上是至关重要的,这样我们就不必先复制内部向量,然后再复制内部的字符串,我们只需要获得它们的所有权即可。
我们实际上可以像求和一样写这个:将向量两两连接起来。由于我们总是重复使用同一个累加向量的分配和内容,所以这个操作是线性时间的。
为了尽量减少增长和重新分配矢量所花费的时间,请预先计算 space 所需的数量。
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> */
.flat_map
的方法很好,但是如果您不想再次克隆字符串,则必须在所有级别上使用 .into_iter()
:(x
是 Vec<String>
).
vecs.into_iter().flat_map(|x| x.into_iter()).collect()
如果你想克隆每个字符串,你可以使用这个:(将 .into_iter()
更改为 .iter()
因为 x
这里是一个 &Vec<String>
并且这两种方法实际上都会产生同样的事情!)
vecs.iter().flat_map(|x| x.iter().map(Clone::clone)).collect()