Search code examples
rustarray-column

Implementing PHP array_column in Rust


I'm in the process of learning Rust, but I could not find an answer to this question.

In PHP, there's the array_column method and it works this way:

given an array of arrays (this would be a a Vector of vectors in Rust):

$records = [
    [1,2,3],
    [1,2,3],
    [1,2,3],
    [1,2,3]
];

if I want to get an array containing all the first elements (a "column") of the inner arrays I can do:

$column = array_column($records, 0);

This way, for example, I get [1,1,1,1]. If I change that 0 with 1, I get [2,2,2,2] and so on.

Since there's no array_column equivalent in Rust (that is: I could not find it), what could be the best way to implement a similar behavior with a vector of vectors?


Solution

  • I decided to play with iterators, as you tried in the comments.

    This version works with any clonable values (numbers included). We iterate over subvectors, and for each we call a get method, which either yields an element of the vector Some(&e) or None if we ask out of bounds.

    and_then then accepts a value from get, and if it was None, then None is returned, otherwise, if it's Some(&e) then Some(e.clone()) is returned, i.e. we clone the value (because we only have the reference to the value from get, we can't store it, we have to copy the value).

    collect then works with Iter<Option<T>>, and it conveniently turns it in Option<Vec<T>>, i.e. it returns None if some Nones were in the iterator (which means some arrays didn't have big enough size), or returns Some(Vec<T>), if everything is fine.

    fn main() {
        let array = vec![
            vec![1, 2, 3, 4],
            vec![1, 2, 3, 4, 5],
            vec![1, 2, 3, 4],
            vec![1, 2, 3, 4],
        ];
        let ac = array_column(&array, 0);
        println!("{:?}", ac); // Some([1, 1, 1, 1])
    
        let ac = array_column(&array, 3);
        println!("{:?}", ac); // Some([4, 4, 4, 4])
    
        let ac = array_column(&array, 4); // None
        println!("{:?}", ac);
    }
    
    fn array_column<T: Clone>(array: &Vec<Vec<T>>, column: usize) -> Option<Vec<T>> {
        array.iter()
            .map( |subvec| subvec.get(column).and_then(|e| Some(e.clone())) )
            .collect()
    }