所以我有一个
Vec<Vec<T>>
,其中第一个向量按一天中的小时进行分组,内部向量按一周中的天进行分组。我想以某种方式转置向量,先按天,然后按小时。 Rust 有没有简单的方法?
编辑:我的意思是,我知道如何用 2 个 for 循环来完成它,但是有没有更智能/更短的方法来实现它的功能
您可以使用一些迭代器:
fn transpose<T>(v: Vec<Vec<T>>) -> Vec<Vec<T>>
where
T: Clone,
{
assert!(!v.is_empty());
(0..v[0].len())
.map(|i| v.iter().map(|inner| inner[i].clone()).collect::<Vec<T>>())
.collect()
}
正如
user4815162342
评论,这是一个没有Clone
的版本:
fn transpose2<T>(v: Vec<Vec<T>>) -> Vec<Vec<T>> {
assert!(!v.is_empty());
let len = v[0].len();
let mut iters: Vec<_> = v.into_iter().map(|n| n.into_iter()).collect();
(0..len)
.map(|_| {
iters
.iter_mut()
.map(|n| n.next().unwrap())
.collect::<Vec<T>>()
})
.collect()
}
问题说“我知道如何用2个for循环来做到这一点,但是有没有一种更智能/更短的方法来实现它的功能”,但这可能是标题的最佳答案。这是一个两
for
循环解决方案,可以避免 T: Clone
并避免为迭代器分配暂存 Vec
:
fn transpose<T>(original: Vec<Vec<T>>) -> Vec<Vec<T>> {
assert!(!original.is_empty());
let mut transposed = (0..original[0].len()).map(|_| vec![]).collect::<Vec<_>>();
for original_row in original {
for (item, transposed_row) in original_row.into_iter().zip(&mut transposed) {
transposed_row.push(item);
}
}
transposed
}
也许有人可以让它比我更“实用”,但这已经有点难以阅读,尽我所能。
这是一种方法
let v = vec![vec![1,2,3,4], vec![5,6,7,8]];
let rows = v.len();
let cols = v[0].len();
let transposed: Vec<Vec<_>> = (0..cols).map(|col| {
(0..rows)
.map(|row| v[row][col])
.collect()
}).collect();
以下方法展示了如果数据类型不具有复制特征并且工作正常,如何避免克隆(这意味着我们重用原始数据并将它们构造成新的结构,而不是像前面的答案所示那样制作副本)以功能性的方式。
fn main() {
let x = vec![
vec![String::from("a"), String::from("b"), String::from("c")],
vec![String::from("d"), String::from("e"), String::from("f")]
];
let n = 3;
// take the iterators out
let mut iters = x
.into_iter()
.map(|u| u.into_iter())
.collect::<Vec<_>>();
// grab elements from iterators and compose the column vector
let transpose = (0..n)
.map(
|_| iters
.iter_mut()
.map(|y| y.next().unwrap())
.collect::<Vec<_>>()
)
.collect::<Vec<_>>();
println!("{:?}", transpose);
}