ditoslav
ditoslav

Reputation: 4892

How to transpose a vector of vectors in Rust?

So I have a Vec<Vec<T>> where the first vector groups by hours of day and the inner vector by days of week. I would like to transpose somehow the vectors to have it first by days then by hours. Is there a simple way to do it in Rust?

EDIT: I mean, I know how to do it with 2 for loops but is there a smarter/shorter way to do it functionally

Upvotes: 15

Views: 11804

Answers (3)

user_name
user_name

Reputation: 11

Here's one way

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

Upvotes: 1

kmdreko
kmdreko

Reputation: 60762

The question says "I know how to do it with 2 for loops but is there a smarter/shorter way to do it functionally", however that it is probably the best answer for the title. Here's a two-for-loop solution that avoids T: Clone and avoids allocating a scratch Vec for iterators:

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
}

Someone could probably make it more "functional" than I, but this is already a bit difficult to read, try as I might.

Upvotes: 1

Netwave
Netwave

Reputation: 42796

You can use some iterators:

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

As user4815162342 comments, here is a version without 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

Upvotes: 23

Related Questions