lowdash/
find.rs

1/// Find the first item in a collection that satisfies a predicate.
2/// If no item satisfies the predicate, return None.
3///
4/// # Arguments
5/// * `collection` - A collection of items.
6/// * `predicate` - A function that takes an item from the collection and returns a boolean.
7///
8/// # Returns
9/// * `Some(&T)` - The first item in the collection that satisfies the predicate.
10/// * `None` - If no item satisfies the predicate.
11///
12/// # Examples
13/// ```rust
14/// use lowdash::find;
15/// let numbers = vec![1, 2, 3, 4, 5];
16/// let predicate = |x: &i32| *x == 3;
17/// let result = find(&numbers, predicate);
18/// assert_eq!(result, Some(&3));
19/// ```
20///
21/// ```rust
22/// use lowdash::find;
23/// let numbers = vec![10, 20, 30, 40];
24/// let result = find(&numbers, |x| *x > 25);
25/// assert_eq!(result, Some(&30));
26/// ```
27///
28/// ```rust
29/// use lowdash::find;
30///
31/// #[derive(Debug, PartialEq)]
32/// struct Person {
33///    name: String,
34///    age: u32,
35/// }
36///
37/// let people = vec![
38///    Person { name: "Alice".to_string(), age: 25 },
39///    Person { name: "Bob".to_string(), age: 30 },
40///    Person { name: "Carol".to_string(), age: 35 },
41/// ];
42///
43/// let result = find(&people, |p| p.age > 30);
44/// assert_eq!(result, Some(&Person { name: "Carol".to_string(), age: 35 }));
45/// ```
46pub fn find<T, F>(collection: &[T], predicate: F) -> Option<&T>
47where
48    F: Fn(&T) -> bool,
49{
50    collection.iter().find(|&item| predicate(item))
51}
52
53#[cfg(test)]
54mod tests {
55    use super::*;
56
57    #[test]
58    fn test_find() {
59        let collection = vec![1, 2, 3, 4, 5];
60        let predicate = |x: &i32| *x == 3;
61        let result = find(&collection, predicate);
62        assert_eq!(result, Some(&3));
63    }
64
65    #[test]
66    fn test_find_with_inline_predicate() {
67        let numbers = vec![10, 20, 30, 40];
68        let result = find(&numbers, |x| *x > 25);
69        assert_eq!(result, Some(&30));
70    }
71
72    #[test]
73    fn test_find_not_found() {
74        let collection = vec![1, 2, 3, 4, 5];
75        let predicate = |x: &i32| *x == 6;
76        let result = find(&collection, predicate);
77        assert_eq!(result, None);
78    }
79
80    #[test]
81    fn test_find_not_found_with_inline_predicate() {
82        let numbers = vec![10, 20, 30, 40];
83        let result = find(&numbers, |x| *x > 50);
84        assert_eq!(result, None);
85    }
86
87    #[test]
88    fn test_find_empty_collection() {
89        let collection: Vec<i32> = vec![];
90        let predicate = |x: &i32| *x == 3;
91        let result = find(&collection, predicate);
92        assert_eq!(result, None);
93    }
94
95    #[test]
96    fn test_find_with_struct() {
97        #[derive(Debug, PartialEq)]
98        struct Person {
99            name: String,
100            age: u32,
101        }
102
103        let people = vec![
104            Person {
105                name: "Alice".to_string(),
106                age: 25,
107            },
108            Person {
109                name: "Bob".to_string(),
110                age: 30,
111            },
112            Person {
113                name: "Carol".to_string(),
114                age: 35,
115            },
116        ];
117
118        let result = find(&people, |p| p.age > 30);
119        assert_eq!(
120            result,
121            Some(&Person {
122                name: "Carol".to_string(),
123                age: 35
124            })
125        );
126
127        let name_result = find(&people, |p| p.name.starts_with("B"));
128        assert_eq!(
129            name_result,
130            Some(&Person {
131                name: "Bob".to_string(),
132                age: 30
133            })
134        );
135
136        let not_found = find(&people, |p| p.age > 40);
137        assert_eq!(not_found, None);
138    }
139
140    #[test]
141    fn test_find_with_floats() {
142        let float_collection = vec![1.1, 2.2, 3.3, 4.4];
143        let predicate = |x: &f64| *x > 2.0;
144        let result = find(&float_collection, predicate);
145        assert_eq!(result, Some(&2.2));
146
147        let not_found = find(&float_collection, |x| *x > 5.0);
148        assert_eq!(not_found, None);
149    }
150
151    #[test]
152    fn test_find_with_negative_floats() {
153        let float_collection = vec![-3.5, -2.2, -1.1, 0.0, 1.1];
154        let predicate = |x: &f64| *x < 0.0;
155        let result = find(&float_collection, predicate);
156        assert_eq!(result, Some(&-3.5));
157    }
158
159    #[test]
160    fn test_find_with_nan_floats() {
161        let float_collection = vec![std::f64::NAN, 2.2, std::f64::NAN, 4.4];
162        let predicate = |x: &f64| x.is_nan();
163        let result = find(&float_collection, predicate);
164        assert!(result.unwrap().is_nan());
165    }
166
167    #[test]
168    fn test_find_with_multiple_matching_floats() {
169        let float_collection = vec![1.1, 2.2, 2.2, 3.3, 4.4];
170        let predicate = |x: &f64| *x == 2.2;
171        let result = find(&float_collection, predicate);
172        assert_eq!(result, Some(&2.2));
173    }
174}