Path: blob/main/crates/polars-arrow/src/compute/boolean.rs
6939 views
//! null-preserving operators such as [`and`], [`or`] and [`not`].1use super::utils::combine_validities_and;2use crate::array::{Array, BooleanArray};3use crate::bitmap::Bitmap;4use crate::datatypes::ArrowDataType;5use crate::scalar::BooleanScalar;67fn assert_lengths(lhs: &BooleanArray, rhs: &BooleanArray) {8assert_eq!(9lhs.len(),10rhs.len(),11"lhs and rhs must have the same length"12);13}1415/// Helper function to implement binary kernels16pub(crate) fn binary_boolean_kernel<F>(17lhs: &BooleanArray,18rhs: &BooleanArray,19op: F,20) -> BooleanArray21where22F: Fn(&Bitmap, &Bitmap) -> Bitmap,23{24assert_lengths(lhs, rhs);25let validity = combine_validities_and(lhs.validity(), rhs.validity());2627let left_buffer = lhs.values();28let right_buffer = rhs.values();2930let values = op(left_buffer, right_buffer);3132BooleanArray::new(ArrowDataType::Boolean, values, validity)33}3435/// Performs `&&` operation on two [`BooleanArray`], combining the validities.36/// # Panics37/// This function panics iff the arrays have different lengths.38/// # Examples39/// ```rust40/// use polars_arrow::array::BooleanArray;41/// use polars_arrow::compute::boolean::and;42///43/// let a = BooleanArray::from(&[Some(false), Some(true), None]);44/// let b = BooleanArray::from(&[Some(true), Some(true), Some(false)]);45/// let and_ab = and(&a, &b);46/// assert_eq!(and_ab, BooleanArray::from(&[Some(false), Some(true), None]));47/// ```48pub fn and(lhs: &BooleanArray, rhs: &BooleanArray) -> BooleanArray {49if lhs.null_count() == 0 && rhs.null_count() == 0 {50let left_buffer = lhs.values();51let right_buffer = rhs.values();5253match (left_buffer.unset_bits(), right_buffer.unset_bits()) {54// all values are `true` on both sides55(0, 0) => {56assert_lengths(lhs, rhs);57return lhs.clone();58},59// all values are `false` on left side60(l, _) if l == lhs.len() => {61assert_lengths(lhs, rhs);62return lhs.clone();63},64// all values are `false` on right side65(_, r) if r == rhs.len() => {66assert_lengths(lhs, rhs);67return rhs.clone();68},69// ignore the rest70_ => {},71}72}7374binary_boolean_kernel(lhs, rhs, |lhs, rhs| lhs & rhs)75}7677/// Performs `||` operation on two [`BooleanArray`], combining the validities.78/// # Panics79/// This function panics iff the arrays have different lengths.80/// # Examples81/// ```rust82/// use polars_arrow::array::BooleanArray;83/// use polars_arrow::compute::boolean::or;84///85/// let a = BooleanArray::from(vec![Some(false), Some(true), None]);86/// let b = BooleanArray::from(vec![Some(true), Some(true), Some(false)]);87/// let or_ab = or(&a, &b);88/// assert_eq!(or_ab, BooleanArray::from(vec![Some(true), Some(true), None]));89/// ```90pub fn or(lhs: &BooleanArray, rhs: &BooleanArray) -> BooleanArray {91if lhs.null_count() == 0 && rhs.null_count() == 0 {92let left_buffer = lhs.values();93let right_buffer = rhs.values();9495match (left_buffer.unset_bits(), right_buffer.unset_bits()) {96// all values are `true` on left side97(0, _) => {98assert_lengths(lhs, rhs);99return lhs.clone();100},101// all values are `true` on right side102(_, 0) => {103assert_lengths(lhs, rhs);104return rhs.clone();105},106// all values on lhs and rhs are `false`107(l, r) if l == lhs.len() && r == rhs.len() => {108assert_lengths(lhs, rhs);109return rhs.clone();110},111// ignore the rest112_ => {},113}114}115116binary_boolean_kernel(lhs, rhs, |lhs, rhs| lhs | rhs)117}118119/// Performs unary `NOT` operation on an arrays. If value is null then the result is also120/// null.121/// # Example122/// ```rust123/// use polars_arrow::array::BooleanArray;124/// use polars_arrow::compute::boolean::not;125///126/// let a = BooleanArray::from(vec![Some(false), Some(true), None]);127/// let not_a = not(&a);128/// assert_eq!(not_a, BooleanArray::from(vec![Some(true), Some(false), None]));129/// ```130pub fn not(array: &BooleanArray) -> BooleanArray {131let values = !array.values();132let validity = array.validity().cloned();133BooleanArray::new(ArrowDataType::Boolean, values, validity)134}135136/// Returns a non-null [`BooleanArray`] with whether each value of the array is null.137/// # Example138/// ```rust139/// use polars_arrow::array::BooleanArray;140/// use polars_arrow::compute::boolean::is_null;141/// # fn main() {142/// let a = BooleanArray::from(vec![Some(false), Some(true), None]);143/// let a_is_null = is_null(&a);144/// assert_eq!(a_is_null, BooleanArray::from_slice(vec![false, false, true]));145/// # }146/// ```147pub fn is_null(input: &dyn Array) -> BooleanArray {148let len = input.len();149150let values = match input.validity() {151None => Bitmap::new_zeroed(len),152Some(buffer) => !buffer,153};154155BooleanArray::new(ArrowDataType::Boolean, values, None)156}157158/// Returns a non-null [`BooleanArray`] with whether each value of the array is not null.159/// # Example160/// ```rust161/// use polars_arrow::array::BooleanArray;162/// use polars_arrow::compute::boolean::is_not_null;163///164/// let a = BooleanArray::from(&vec![Some(false), Some(true), None]);165/// let a_is_not_null = is_not_null(&a);166/// assert_eq!(a_is_not_null, BooleanArray::from_slice(&vec![true, true, false]));167/// ```168pub fn is_not_null(input: &dyn Array) -> BooleanArray {169let values = match input.validity() {170None => Bitmap::new_with_value(true, input.len()),171Some(buffer) => buffer.clone(),172};173BooleanArray::new(ArrowDataType::Boolean, values, None)174}175176/// Performs `AND` operation on an array and a scalar value. If either left or right value177/// is null then the result is also null.178/// # Example179/// ```rust180/// use polars_arrow::array::BooleanArray;181/// use polars_arrow::compute::boolean::and_scalar;182/// use polars_arrow::scalar::BooleanScalar;183///184/// let array = BooleanArray::from_slice(&[false, false, true, true]);185/// let scalar = BooleanScalar::new(Some(true));186/// let result = and_scalar(&array, &scalar);187/// assert_eq!(result, BooleanArray::from_slice(&[false, false, true, true]));188///189/// ```190pub fn and_scalar(array: &BooleanArray, scalar: &BooleanScalar) -> BooleanArray {191match scalar.value() {192Some(true) => array.clone(),193Some(false) => {194let values = Bitmap::new_zeroed(array.len());195BooleanArray::new(ArrowDataType::Boolean, values, array.validity().cloned())196},197None => BooleanArray::new_null(ArrowDataType::Boolean, array.len()),198}199}200201/// Performs `OR` operation on an array and a scalar value. If either left or right value202/// is null then the result is also null.203/// # Example204/// ```rust205/// use polars_arrow::array::BooleanArray;206/// use polars_arrow::compute::boolean::or_scalar;207/// use polars_arrow::scalar::BooleanScalar;208/// # fn main() {209/// let array = BooleanArray::from_slice(&[false, false, true, true]);210/// let scalar = BooleanScalar::new(Some(true));211/// let result = or_scalar(&array, &scalar);212/// assert_eq!(result, BooleanArray::from_slice(&[true, true, true, true]));213/// # }214/// ```215pub fn or_scalar(array: &BooleanArray, scalar: &BooleanScalar) -> BooleanArray {216match scalar.value() {217Some(true) => BooleanArray::new(218ArrowDataType::Boolean,219Bitmap::new_with_value(true, array.len()),220array.validity().cloned(),221),222Some(false) => array.clone(),223None => BooleanArray::new_null(ArrowDataType::Boolean, array.len()),224}225}226227/// Returns whether any of the values in the array are `true`.228///229/// Null values are ignored.230///231/// # Example232///233/// ```234/// use polars_arrow::array::BooleanArray;235/// use polars_arrow::compute::boolean::any;236///237/// let a = BooleanArray::from(&[Some(true), Some(false)]);238/// let b = BooleanArray::from(&[Some(false), Some(false)]);239/// let c = BooleanArray::from(&[None, Some(false)]);240///241/// assert_eq!(any(&a), true);242/// assert_eq!(any(&b), false);243/// assert_eq!(any(&c), false);244/// ```245pub fn any(array: &BooleanArray) -> bool {246if array.is_empty() {247false248} else if array.null_count() > 0 {249array.into_iter().any(|v| v == Some(true))250} else {251let vals = array.values();252vals.unset_bits() != vals.len()253}254}255256/// Returns whether all values in the array are `true`.257///258/// Null values are ignored.259///260/// # Example261///262/// ```263/// use polars_arrow::array::BooleanArray;264/// use polars_arrow::compute::boolean::all;265///266/// let a = BooleanArray::from(&[Some(true), Some(true)]);267/// let b = BooleanArray::from(&[Some(false), Some(true)]);268/// let c = BooleanArray::from(&[None, Some(true)]);269///270/// assert_eq!(all(&a), true);271/// assert_eq!(all(&b), false);272/// assert_eq!(all(&c), true);273/// ```274pub fn all(array: &BooleanArray) -> bool {275if array.is_empty() {276true277} else if array.null_count() > 0 {278!array.into_iter().any(|v| v == Some(false))279} else {280let vals = array.values();281vals.unset_bits() == 0282}283}284285286