1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
/// Drain and filter at the same time, accepts a `mutable vector ref` and `predicate`.
/// The `predicate` receives a `vector element ref` for the current iteration and
/// in-place removes the element from the vector, if `predicate` returns `true`.
/// Returns and array of `removed` elements back.
///
/// ## Examples
///
/// ```
/// use cs_utils::{drain_filter, random_bool};
///
/// let mut test_vector = vec![
/// random_bool(),
/// random_bool(),
/// random_bool(),
/// random_bool(),
/// random_bool(),
/// random_bool(),
/// random_bool(),
/// random_bool(),
/// random_bool(),
/// random_bool(),
/// random_bool(),
/// ];
///
/// let removed_items = drain_filter(
/// &mut test_vector,
/// |el| {
/// return *el;
/// },
/// );
///
/// assert!(
/// !removed_items.contains(&false),
/// "Removed items must not contain \"false\" values.",
/// );
///
/// assert!(
/// !test_vector.contains(&true),
/// "Removed items must not contain \"true\" values.",
/// );
/// ```
pub fn drain_filter<T>(vector: &mut Vec<T>, mut predicate: impl FnMut(&T) -> bool) -> Vec<T> {
let mut result = vec![];
let mut i = 0;
while i < vector.len() {
let item = &vector[i];
if predicate(item) {
let removed_item = vector.swap_remove(i);
result.push(removed_item);
// since we swapped with the last vector item, don't increment
// the index, - the swapped item must be checked too
continue;
}
i += 1;
}
return result;
}
#[cfg(test)]
mod tests {
use crate::drain_filter;
#[test]
fn drains_the_vector() {
let mut test_vector = vec![
true,
false,
false,
true,
true,
false,
false,
false,
];
let removed = drain_filter(&mut test_vector, |el| {
return *el;
});
assert_eq!(
removed.len(),
3,
"Must remove all elements equal to \"true\"."
);
assert!(
!removed.contains(&false),
"Removed elements vector must not contain \"false\" values."
);
assert_eq!(
test_vector.len(),
5,
"Original vector must retain \"false\" values."
);
assert!(
!test_vector.contains(&true),
"Original vector must not contain \"true\" values."
);
}
#[test]
fn works_with_non_clone_items() {
struct TestStruct {
pub flag: bool,
}
let mut test_vector = vec![
TestStruct { flag: false },
TestStruct { flag: true },
TestStruct { flag: false },
TestStruct { flag: true },
TestStruct { flag: false },
TestStruct { flag: true },
TestStruct { flag: false },
TestStruct { flag: true },
TestStruct { flag: true },
];
let removed = drain_filter(&mut test_vector, |el| {
return el.flag;
});
assert_eq!(
removed.len(),
5,
"Must remove all elements equal to \"true\"."
);
assert_eq!(
test_vector.len(),
4,
"Must retain all elements equal to \"false\"."
);
}
}