Implementing a Generic where Clause for Filtering Collections in Rust
This challenge asks you to build a robust and flexible filtering mechanism for Rust collections. You'll implement a function that takes a collection and a predicate (a function that returns a boolean) and returns a new collection containing only the elements that satisfy the predicate. This is akin to the where clause found in some other languages for filtering data, and it's a fundamental operation in data processing and functional programming.
Problem Description
You need to create a generic Rust function named filter_collection that accepts two arguments:
collection: A slice of elements of any typeT.predicate: A closure or function that takes a reference to an element of typeTand returns abool.
The filter_collection function should iterate through the input collection and apply the predicate to each element. If the predicate returns true for an element, that element should be included in the resulting collection. The function should return a new Vec<T> containing all the elements that passed the filter.
Key Requirements:
- The function must be generic over the type
Tof the elements in the collection. - The
predicatemust be able to accept a reference to an element (&T). - The function should return a
Vec<T>containing the filtered elements. - The original collection should not be modified.
Expected Behavior:
The function should return a new vector containing only the elements for which the provided predicate evaluates to true. The order of elements in the output vector should be the same as their order in the input collection.
Edge Cases to Consider:
- An empty input collection.
- A predicate that always returns
true(should return a copy of the original collection). - A predicate that always returns
false(should return an empty collection).
Examples
Example 1: Filtering a vector of integers.
Input:
collection: &[1, 2, 3, 4, 5]
predicate: |&x| x % 2 == 0 // Keep even numbers
Output:
[2, 4]
Explanation: The predicate `x % 2 == 0` is applied to each element. `2` and `4` are even, so they are included in the output.
Example 2: Filtering a vector of strings.
Input:
collection: &["apple", "banana", "cherry", "date"]
predicate: |&s| s.len() > 5 // Keep strings longer than 5 characters
Output:
["banana", "cherry"]
Explanation: The predicate `s.len() > 5` is applied. "banana" (6 chars) and "cherry" (6 chars) satisfy the condition.
Example 3: Filtering with an empty input collection.
Input:
collection: &[]
predicate: |&x| x > 10
Output:
[]
Explanation: An empty input collection results in an empty output collection, regardless of the predicate.
Constraints
- The input
collectionwill be a slice (&[T]). - The
predicatewill be a type that implementsFn(&T) -> bool. - The type
Tmust implement theClonetrait to allow copying elements into the newVec. This is to ensure the original collection is not modified and we can return owned values. - The function should be reasonably efficient for typical collection sizes. No specific Big O complexity is mandated, but aim for a straightforward iterative approach.
Notes
- Remember that Rust's
Vecneeds to own its elements. Since the input is a slice of references, you'll need toclonethe elements that satisfy the predicate before pushing them into the newVec. - Consider how you will express the generic type
Tand the predicate argument in your function signature. - This is a great opportunity to practice Rust's powerful generics and trait bounds.