Sling Academy
Home/Rust/Filtering a Vec in Rust using filter, retain, and drain

Filtering a Vec in Rust using filter, retain, and drain

Last updated: January 04, 2025

When working with collections in Rust, specifically Vec, there's often a need to filter items based on certain criteria. Rust offers several ways to filter elements in a Vec: filter, retain, and drain. Each method serves different purposes and provides unique advantages. This article will explore how to utilize these techniques effectively.

filter Method

The filter method is part of Rust's iterator API. It creates a new iterator that only includes elements which satisfy a specified condition. It's important to note that filter does not modify the original collection but rather produces a new iterator.

fn main() {
    let numbers = vec![1, 2, 3, 4, 5];
    let even_numbers: Vec = numbers.iter().filter(|&x| x % 2 == 0).cloned().collect();
    println!("Even Numbers: {:?}", even_numbers);
}

In this example, we have a Vec of numbers, and we use filter to create a new collection of even numbers. We chain cloned() to convert from an iterator of references to an iterator of values.

retain Method

The retain method modifies the original Vec by keeping elements that match a given predicate and removing those that don't. This method is more efficient when you wish to update the collection in place because it avoids allocating a new Vec.

fn main() {
    let mut numbers = vec![1, 2, 3, 4, 5];
    numbers.retain(|&x| x % 2 == 0);
    println!("Even Numbers: {:?}", numbers);
}

Here, the original numbers vector is modified to only include even integers, effectively filtering it in-place.

drain Method

The drain method offers a way of filtering by allowing you to safely remove elements from a Vec while also performing operations over the removed items. It creates an iterator that yields elements removed from the collection.

fn main() {
    let mut numbers = vec![1, 2, 3, 4, 5];
    let removed: Vec = numbers.drain_filter(|x| *x % 2 != 0).collect();
    println!("Unchanged Vector: {:?}", numbers);
    println!("Removed Odd Numbers: {:?}", removed);
}

In this example, the elements not divisible by 2 are drained from the Vec, and we obtain an iterator over those elements. After this operation, numbers retains only the even integers, while removed captures what was filtered out.

Performance Considerations

Choosing between these methods involves considering how each affects performance and what idiomatic Rust suggests. retain modifies in place and tends to offer better performance when the vector needs alteration without concern for the removed data. In contrast, drain can be more useful when you need to both remove and process elements concurrently.

Summary

Rust provides versatile methods for filtering collections in a type-safe, efficient manner. Parameters such as whether you want to filter into a new collection, modify a vector in place, or need access to the removed elements will guide your choice among filter, retain, and drain. Each offers distinct advantages depending on the requirements of the task.

Next Article: Rust - Mapping vector elements to new values with map, iter_mut, and collect

Previous Article: Rust - Searching in vectors: find, position, and binary_search for sorted data

Series: Collections in Rust

Rust

You May Also Like

  • E0557 in Rust: Feature Has Been Removed or Is Unavailable in the Stable Channel
  • Network Protocol Handling Concurrency in Rust with async/await
  • Using the anyhow and thiserror Crates for Better Rust Error Tests
  • Rust - Investigating partial moves when pattern matching on vector or HashMap elements
  • Rust - Handling nested or hierarchical HashMaps for complex data relationships
  • Rust - Combining multiple HashMaps by merging keys and values
  • Composing Functionality in Rust Through Multiple Trait Bounds
  • E0437 in Rust: Unexpected `#` in macro invocation or attribute
  • Integrating I/O and Networking in Rust’s Async Concurrency
  • E0178 in Rust: Conflicting implementations of the same trait for a type
  • Utilizing a Reactor Pattern in Rust for Event-Driven Architectures
  • Parallelizing CPU-Intensive Work with Rust’s rayon Crate
  • Managing WebSocket Connections in Rust for Real-Time Apps
  • Downloading Files in Rust via HTTP for CLI Tools
  • Mocking Network Calls in Rust Tests with the surf or reqwest Crates
  • Rust - Designing advanced concurrency abstractions using generic channels or locks
  • Managing code expansion in debug builds with heavy usage of generics in Rust
  • Implementing parse-from-string logic for generic numeric types in Rust
  • Rust.- Refining trait bounds at implementation time for more specialized behavior