如何在 Rust 中转置一个向量的向量?

11

我有一个 Vec<Vec<T>>,其中第一个向量按一天中的小时分组,内部向量按一周中的天分组。 我想要转置这些向量,先按天,然后再按小时排序。在Rust中有简单的方法吗?

编辑:我的意思是,我知道如何使用2个for循环来完成,但是否有更聪明/更短的函数式方法可以实现它。


请更清楚地解释“第一个向量按照一天中的小时分组,内部向量按照一周中的天数分组”。这里的“T”是什么,也许是“DateTime”类型?您能展示一个输入和期望输出的例子吗? - trent
2
没关系。我们可以把它称作 T,就像答案一样。 - ditoslav
3个回答

18
你可以使用一些迭代器:
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()
}

Playground


2
由于值的数量相同,如果有一个不需要 T: Clone 的版本,那将是很好的 - 也许通过排空内部向量。 - user4815162342
1
不错的编辑!我想到了这个想法,首先反转内部向量,然后从末尾弹出它们,但是一个into_iters的向量更好,也更快。 - user4815162342
1
这个功能在某个流行的库中存在吗? - TheChubbyPanda

0

这是一种方法

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();

0
问题说:“我知道如何使用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
}

有人可能比我更能将它变得更“函数化”,但无论我怎么尝试,这已经有点难以阅读了。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接