# Better way to filter Vec<Vec<f64>> by indices

I'm on my 12th hour of coding today (I know you've been there ) and I'm seeking assistance to solve the following problem. The snippet below works and produces the desired result but, my God is it ugly:

``````fn main() {
let data = vec![
vec![0.05, 0.12, 0.8],
vec![0.18, 0.22, 1.9],
vec![0.31, 0.35, 3.2],
vec![0.42, 0.38, 4.6],
vec![0.5, 0.49, 5.0]
];

// I only want to retain the 0th and 2nd elements from each
// of the internal vecs
let idxs: Vec<usize> = vec![0,2];

let data: Vec<Vec<f64>> = data.iter()
.map(|el| {
el.iter()
.enumerate()
.filter(|(i, _)| idxs.contains(i))
.map(|e| e.1)
.cloned()
.collect()
})
.collect();

println!("{:#?}", data);
}
``````

What's a better way to do this (in terms of performance/code cleanliness)?

I think pattern match may be much better for this problem:

``````let data = data.into_iter()
.filter_map(|el| {
if let [a, _, b] = el[..] {
Some(vec![a, b])
} else {
None
}
})
.collect::<Vec<_>>();
``````
4 Likes

This is very nice, thank you. Is there a way to make it dynamic? In my program, the `idxs` vec is passed in by the user. How would I go from `vec![0,2,3]`, for example, to `[a,_,b,c]` and then to `Some(vec![a,b,c])`?

You don't need to do it functional style, for loops seem appropriate here: Rust Playground

1 Like

In that case, if the indices are dynamic, why don't you simply index into the inner vectors? Like this:

``````let data: Vec<Vec<f64>> = data.iter()
.map(|inner| idxs.iter().map(|&i| inner[i]).collect())
.collect();
``````
2 Likes

That's a beautiful solution - thank you This is really nice too. I'll try to benchmark the two approaches later to see what's more performant. Any ideas though as to which will perform better?

I agree, that's the best one Not sure if youre aware, though, but our solutions don't quite behave the same as yours, because they panic if an index a user gave was invalid. You'd need to handle that, e.g. like this:

``````let data: Vec<Vec<f64>> = data.iter()
.map(|inner| idxs.iter().filter_map(|&i| inner.get(i)).collect())
.collect();
``````
1 Like

Tough to tell, in my solution you could give a capacity to the vecs to allocate exactly right. Not sure if that can work with the functional solution (the user-vec is dynamic, right). But that might behave better wrt bounds checks.

Truth be told though, measure if you're interested, but ignore it unless a benchmark tells you this is relevant. It's really a micro-optimization, go for readability first.

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.