polars_arrow/compute/boolean.rs
1//! null-preserving operators such as [`and`], [`or`] and [`not`].
2use super::utils::combine_validities_and;
3use crate::array::{Array, BooleanArray};
4use crate::bitmap::Bitmap;
5use crate::datatypes::ArrowDataType;
6use crate::scalar::BooleanScalar;
7
8fn assert_lengths(lhs: &BooleanArray, rhs: &BooleanArray) {
9 assert_eq!(
10 lhs.len(),
11 rhs.len(),
12 "lhs and rhs must have the same length"
13 );
14}
15
16/// Helper function to implement binary kernels
17pub(crate) fn binary_boolean_kernel<F>(
18 lhs: &BooleanArray,
19 rhs: &BooleanArray,
20 op: F,
21) -> BooleanArray
22where
23 F: Fn(&Bitmap, &Bitmap) -> Bitmap,
24{
25 assert_lengths(lhs, rhs);
26 let validity = combine_validities_and(lhs.validity(), rhs.validity());
27
28 let left_buffer = lhs.values();
29 let right_buffer = rhs.values();
30
31 let values = op(left_buffer, right_buffer);
32
33 BooleanArray::new(ArrowDataType::Boolean, values, validity)
34}
35
36/// Performs `&&` operation on two [`BooleanArray`], combining the validities.
37/// # Panics
38/// This function panics iff the arrays have different lengths.
39/// # Examples
40/// ```rust
41/// use polars_arrow::array::BooleanArray;
42/// use polars_arrow::compute::boolean::and;
43///
44/// let a = BooleanArray::from(&[Some(false), Some(true), None]);
45/// let b = BooleanArray::from(&[Some(true), Some(true), Some(false)]);
46/// let and_ab = and(&a, &b);
47/// assert_eq!(and_ab, BooleanArray::from(&[Some(false), Some(true), None]));
48/// ```
49pub fn and(lhs: &BooleanArray, rhs: &BooleanArray) -> BooleanArray {
50 if lhs.null_count() == 0 && rhs.null_count() == 0 {
51 let left_buffer = lhs.values();
52 let right_buffer = rhs.values();
53
54 match (left_buffer.unset_bits(), right_buffer.unset_bits()) {
55 // all values are `true` on both sides
56 (0, 0) => {
57 assert_lengths(lhs, rhs);
58 return lhs.clone();
59 },
60 // all values are `false` on left side
61 (l, _) if l == lhs.len() => {
62 assert_lengths(lhs, rhs);
63 return lhs.clone();
64 },
65 // all values are `false` on right side
66 (_, r) if r == rhs.len() => {
67 assert_lengths(lhs, rhs);
68 return rhs.clone();
69 },
70 // ignore the rest
71 _ => {},
72 }
73 }
74
75 binary_boolean_kernel(lhs, rhs, |lhs, rhs| lhs & rhs)
76}
77
78/// Performs `||` operation on two [`BooleanArray`], combining the validities.
79/// # Panics
80/// This function panics iff the arrays have different lengths.
81/// # Examples
82/// ```rust
83/// use polars_arrow::array::BooleanArray;
84/// use polars_arrow::compute::boolean::or;
85///
86/// let a = BooleanArray::from(vec![Some(false), Some(true), None]);
87/// let b = BooleanArray::from(vec![Some(true), Some(true), Some(false)]);
88/// let or_ab = or(&a, &b);
89/// assert_eq!(or_ab, BooleanArray::from(vec![Some(true), Some(true), None]));
90/// ```
91pub fn or(lhs: &BooleanArray, rhs: &BooleanArray) -> BooleanArray {
92 if lhs.null_count() == 0 && rhs.null_count() == 0 {
93 let left_buffer = lhs.values();
94 let right_buffer = rhs.values();
95
96 match (left_buffer.unset_bits(), right_buffer.unset_bits()) {
97 // all values are `true` on left side
98 (0, _) => {
99 assert_lengths(lhs, rhs);
100 return lhs.clone();
101 },
102 // all values are `true` on right side
103 (_, 0) => {
104 assert_lengths(lhs, rhs);
105 return rhs.clone();
106 },
107 // all values on lhs and rhs are `false`
108 (l, r) if l == lhs.len() && r == rhs.len() => {
109 assert_lengths(lhs, rhs);
110 return rhs.clone();
111 },
112 // ignore the rest
113 _ => {},
114 }
115 }
116
117 binary_boolean_kernel(lhs, rhs, |lhs, rhs| lhs | rhs)
118}
119
120/// Performs unary `NOT` operation on an arrays. If value is null then the result is also
121/// null.
122/// # Example
123/// ```rust
124/// use polars_arrow::array::BooleanArray;
125/// use polars_arrow::compute::boolean::not;
126///
127/// let a = BooleanArray::from(vec![Some(false), Some(true), None]);
128/// let not_a = not(&a);
129/// assert_eq!(not_a, BooleanArray::from(vec![Some(true), Some(false), None]));
130/// ```
131pub fn not(array: &BooleanArray) -> BooleanArray {
132 let values = !array.values();
133 let validity = array.validity().cloned();
134 BooleanArray::new(ArrowDataType::Boolean, values, validity)
135}
136
137/// Returns a non-null [`BooleanArray`] with whether each value of the array is null.
138/// # Example
139/// ```rust
140/// use polars_arrow::array::BooleanArray;
141/// use polars_arrow::compute::boolean::is_null;
142/// # fn main() {
143/// let a = BooleanArray::from(vec![Some(false), Some(true), None]);
144/// let a_is_null = is_null(&a);
145/// assert_eq!(a_is_null, BooleanArray::from_slice(vec![false, false, true]));
146/// # }
147/// ```
148pub fn is_null(input: &dyn Array) -> BooleanArray {
149 let len = input.len();
150
151 let values = match input.validity() {
152 None => Bitmap::new_zeroed(len),
153 Some(buffer) => !buffer,
154 };
155
156 BooleanArray::new(ArrowDataType::Boolean, values, None)
157}
158
159/// Returns a non-null [`BooleanArray`] with whether each value of the array is not null.
160/// # Example
161/// ```rust
162/// use polars_arrow::array::BooleanArray;
163/// use polars_arrow::compute::boolean::is_not_null;
164///
165/// let a = BooleanArray::from(&vec![Some(false), Some(true), None]);
166/// let a_is_not_null = is_not_null(&a);
167/// assert_eq!(a_is_not_null, BooleanArray::from_slice(&vec![true, true, false]));
168/// ```
169pub fn is_not_null(input: &dyn Array) -> BooleanArray {
170 let values = match input.validity() {
171 None => Bitmap::new_with_value(true, input.len()),
172 Some(buffer) => buffer.clone(),
173 };
174 BooleanArray::new(ArrowDataType::Boolean, values, None)
175}
176
177/// Performs `AND` operation on an array and a scalar value. If either left or right value
178/// is null then the result is also null.
179/// # Example
180/// ```rust
181/// use polars_arrow::array::BooleanArray;
182/// use polars_arrow::compute::boolean::and_scalar;
183/// use polars_arrow::scalar::BooleanScalar;
184///
185/// let array = BooleanArray::from_slice(&[false, false, true, true]);
186/// let scalar = BooleanScalar::new(Some(true));
187/// let result = and_scalar(&array, &scalar);
188/// assert_eq!(result, BooleanArray::from_slice(&[false, false, true, true]));
189///
190/// ```
191pub fn and_scalar(array: &BooleanArray, scalar: &BooleanScalar) -> BooleanArray {
192 match scalar.value() {
193 Some(true) => array.clone(),
194 Some(false) => {
195 let values = Bitmap::new_zeroed(array.len());
196 BooleanArray::new(ArrowDataType::Boolean, values, array.validity().cloned())
197 },
198 None => BooleanArray::new_null(ArrowDataType::Boolean, array.len()),
199 }
200}
201
202/// Performs `OR` operation on an array and a scalar value. If either left or right value
203/// is null then the result is also null.
204/// # Example
205/// ```rust
206/// use polars_arrow::array::BooleanArray;
207/// use polars_arrow::compute::boolean::or_scalar;
208/// use polars_arrow::scalar::BooleanScalar;
209/// # fn main() {
210/// let array = BooleanArray::from_slice(&[false, false, true, true]);
211/// let scalar = BooleanScalar::new(Some(true));
212/// let result = or_scalar(&array, &scalar);
213/// assert_eq!(result, BooleanArray::from_slice(&[true, true, true, true]));
214/// # }
215/// ```
216pub fn or_scalar(array: &BooleanArray, scalar: &BooleanScalar) -> BooleanArray {
217 match scalar.value() {
218 Some(true) => BooleanArray::new(
219 ArrowDataType::Boolean,
220 Bitmap::new_with_value(true, array.len()),
221 array.validity().cloned(),
222 ),
223 Some(false) => array.clone(),
224 None => BooleanArray::new_null(ArrowDataType::Boolean, array.len()),
225 }
226}
227
228/// Returns whether any of the values in the array are `true`.
229///
230/// Null values are ignored.
231///
232/// # Example
233///
234/// ```
235/// use polars_arrow::array::BooleanArray;
236/// use polars_arrow::compute::boolean::any;
237///
238/// let a = BooleanArray::from(&[Some(true), Some(false)]);
239/// let b = BooleanArray::from(&[Some(false), Some(false)]);
240/// let c = BooleanArray::from(&[None, Some(false)]);
241///
242/// assert_eq!(any(&a), true);
243/// assert_eq!(any(&b), false);
244/// assert_eq!(any(&c), false);
245/// ```
246pub fn any(array: &BooleanArray) -> bool {
247 if array.is_empty() {
248 false
249 } else if array.null_count() > 0 {
250 array.into_iter().any(|v| v == Some(true))
251 } else {
252 let vals = array.values();
253 vals.unset_bits() != vals.len()
254 }
255}
256
257/// Returns whether all values in the array are `true`.
258///
259/// Null values are ignored.
260///
261/// # Example
262///
263/// ```
264/// use polars_arrow::array::BooleanArray;
265/// use polars_arrow::compute::boolean::all;
266///
267/// let a = BooleanArray::from(&[Some(true), Some(true)]);
268/// let b = BooleanArray::from(&[Some(false), Some(true)]);
269/// let c = BooleanArray::from(&[None, Some(true)]);
270///
271/// assert_eq!(all(&a), true);
272/// assert_eq!(all(&b), false);
273/// assert_eq!(all(&c), true);
274/// ```
275pub fn all(array: &BooleanArray) -> bool {
276 if array.is_empty() {
277 true
278 } else if array.null_count() > 0 {
279 !array.into_iter().any(|v| v == Some(false))
280 } else {
281 let vals = array.values();
282 vals.unset_bits() == 0
283 }
284}