Hone logo
Hone
Problems

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:

  1. collection: A slice of elements of any type T.
  2. predicate: A closure or function that takes a reference to an element of type T and returns a bool.

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 T of the elements in the collection.
  • The predicate must 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 collection will be a slice (&[T]).
  • The predicate will be a type that implements Fn(&T) -> bool.
  • The type T must implement the Clone trait to allow copying elements into the new Vec. 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 Vec needs to own its elements. Since the input is a slice of references, you'll need to clone the elements that satisfy the predicate before pushing them into the new Vec.
  • Consider how you will express the generic type T and the predicate argument in your function signature.
  • This is a great opportunity to practice Rust's powerful generics and trait bounds.
Loading editor...
rust