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?
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 None
s 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()
}