diff --git a/src/compute/boolean.rs b/src/compute/boolean.rs index 39084400f96..46d72669541 100644 --- a/src/compute/boolean.rs +++ b/src/compute/boolean.rs @@ -2,21 +2,20 @@ use crate::array::{Array, BooleanArray}; use crate::bitmap::{Bitmap, MutableBitmap}; use crate::datatypes::DataType; -use crate::error::{Error, Result}; use crate::scalar::BooleanScalar; use super::utils::combine_validities; /// Helper function to implement binary kernels -fn binary_boolean_kernel(lhs: &BooleanArray, rhs: &BooleanArray, op: F) -> Result +fn binary_boolean_kernel(lhs: &BooleanArray, rhs: &BooleanArray, op: F) -> BooleanArray where F: Fn(&Bitmap, &Bitmap) -> Bitmap, { - if lhs.len() != rhs.len() { - return Err(Error::InvalidArgumentError( - "Cannot perform bitwise operation on arrays of different length".to_string(), - )); - } + assert_eq!( + lhs.len(), + rhs.len(), + "lhs and rhs must have the same length" + ); let validity = combine_validities(lhs.validity(), rhs.validity()); @@ -25,48 +24,40 @@ where let values = op(left_buffer, right_buffer); - Ok(BooleanArray::new(DataType::Boolean, values, validity)) + BooleanArray::new(DataType::Boolean, values, validity) } -/// Performs `AND` operation on two arrays. If either left or right value is null then the -/// result is also null. -/// # Error -/// This function errors when the arrays have different lengths. -/// # Example +/// Performs `&&` operation on two [`BooleanArray`], combining the validities. +/// # Panics +/// This function panics iff the arrays have different lengths. +/// # Examples /// ```rust /// use arrow2::array::BooleanArray; -/// use arrow2::error::Result; /// use arrow2::compute::boolean::and; -/// # fn main() -> Result<()> { +/// /// let a = BooleanArray::from(&[Some(false), Some(true), None]); /// let b = BooleanArray::from(&[Some(true), Some(true), Some(false)]); -/// let and_ab = and(&a, &b)?; +/// let and_ab = and(&a, &b); /// assert_eq!(and_ab, BooleanArray::from(&[Some(false), Some(true), None])); -/// # Ok(()) -/// # } /// ``` -pub fn and(lhs: &BooleanArray, rhs: &BooleanArray) -> Result { +pub fn and(lhs: &BooleanArray, rhs: &BooleanArray) -> BooleanArray { binary_boolean_kernel(lhs, rhs, |lhs, rhs| lhs & rhs) } -/// Performs `OR` operation on two arrays. If either left or right value is null then the -/// result is also null. -/// # Error -/// This function errors when the arrays have different lengths. -/// # Example +/// Performs `||` operation on two [`BooleanArray`], combining the validities. +/// # Panics +/// This function panics iff the arrays have different lengths. +/// # Examples /// ```rust /// use arrow2::array::BooleanArray; -/// use arrow2::error::Result; /// use arrow2::compute::boolean::or; -/// # fn main() -> Result<()> { +/// /// let a = BooleanArray::from(vec![Some(false), Some(true), None]); /// let b = BooleanArray::from(vec![Some(true), Some(true), Some(false)]); -/// let or_ab = or(&a, &b)?; +/// let or_ab = or(&a, &b); /// assert_eq!(or_ab, BooleanArray::from(vec![Some(true), Some(true), None])); -/// # Ok(()) -/// # } /// ``` -pub fn or(lhs: &BooleanArray, rhs: &BooleanArray) -> Result { +pub fn or(lhs: &BooleanArray, rhs: &BooleanArray) -> BooleanArray { binary_boolean_kernel(lhs, rhs, |lhs, rhs| lhs | rhs) } @@ -76,11 +67,10 @@ pub fn or(lhs: &BooleanArray, rhs: &BooleanArray) -> Result { /// ```rust /// use arrow2::array::BooleanArray; /// use arrow2::compute::boolean::not; -/// # fn main() { +/// /// let a = BooleanArray::from(vec![Some(false), Some(true), None]); /// let not_a = not(&a); /// assert_eq!(not_a, BooleanArray::from(vec![Some(true), Some(false), None])); -/// # } /// ``` pub fn not(array: &BooleanArray) -> BooleanArray { let values = !array.values(); @@ -88,9 +78,7 @@ pub fn not(array: &BooleanArray) -> BooleanArray { BooleanArray::new(DataType::Boolean, values, validity) } -/// Returns a non-null [BooleanArray] with whether each value of the array is null. -/// # Error -/// This function never errors. +/// Returns a non-null [`BooleanArray`] with whether each value of the array is null. /// # Example /// ```rust /// use arrow2::array::BooleanArray; @@ -112,16 +100,15 @@ pub fn is_null(input: &dyn Array) -> BooleanArray { BooleanArray::new(DataType::Boolean, values, None) } -/// Returns a non-null [BooleanArray] with whether each value of the array is not null. +/// Returns a non-null [`BooleanArray`] with whether each value of the array is not null. /// # Example /// ```rust /// use arrow2::array::BooleanArray; /// use arrow2::compute::boolean::is_not_null; -/// # fn main() { +/// /// let a = BooleanArray::from(&vec![Some(false), Some(true), None]); /// let a_is_not_null = is_not_null(&a); /// assert_eq!(a_is_not_null, BooleanArray::from_slice(&vec![true, true, false])); -/// # } /// ``` pub fn is_not_null(input: &dyn Array) -> BooleanArray { let values = match input.validity() { @@ -142,12 +129,12 @@ pub fn is_not_null(input: &dyn Array) -> BooleanArray { /// use arrow2::array::BooleanArray; /// use arrow2::compute::boolean::and_scalar; /// use arrow2::scalar::BooleanScalar; -/// # fn main() { +/// /// let array = BooleanArray::from_slice(&[false, false, true, true]); /// let scalar = BooleanScalar::new(Some(true)); /// let result = and_scalar(&array, &scalar); /// assert_eq!(result, BooleanArray::from_slice(&[false, false, true, true])); -/// # } +/// /// ``` pub fn and_scalar(array: &BooleanArray, scalar: &BooleanScalar) -> BooleanArray { match scalar.value() { @@ -186,7 +173,7 @@ pub fn or_scalar(array: &BooleanArray, scalar: &BooleanScalar) -> BooleanArray { } } -/// Check if any of the values in the array is `true` +/// Returns whether any of the values in the array is `true` pub fn any(array: &BooleanArray) -> bool { if array.is_empty() { false diff --git a/src/compute/boolean_kleene.rs b/src/compute/boolean_kleene.rs index 7bd412bfce3..48d90433ee9 100644 --- a/src/compute/boolean_kleene.rs +++ b/src/compute/boolean_kleene.rs @@ -1,35 +1,31 @@ //! Boolean operators of [Kleene logic](https://en.wikipedia.org/wiki/Three-valued_logic#Kleene_and_Priest_logics). use crate::datatypes::DataType; -use crate::error::{Error, Result}; use crate::scalar::BooleanScalar; use crate::{ - array::BooleanArray, + array::{Array, BooleanArray}, bitmap::{binary, quaternary, ternary, unary, Bitmap, MutableBitmap}, }; /// Logical 'or' operation on two arrays with [Kleene logic](https://en.wikipedia.org/wiki/Three-valued_logic#Kleene_and_Priest_logics) -/// # Errors -/// This function errors if the operands have different lengths. +/// # Panics +/// This function panics iff the arrays have a different length /// # Example /// /// ```rust -/// # use arrow2::error::Result; /// use arrow2::array::BooleanArray; /// use arrow2::compute::boolean_kleene::or; -/// # fn main() -> Result<()> { +/// /// let a = BooleanArray::from(&[Some(true), Some(false), None]); /// let b = BooleanArray::from(&[None, None, None]); -/// let or_ab = or(&a, &b)?; +/// let or_ab = or(&a, &b); /// assert_eq!(or_ab, BooleanArray::from(&[Some(true), None, None])); -/// # Ok(()) -/// # } /// ``` -pub fn or(lhs: &BooleanArray, rhs: &BooleanArray) -> Result { - if lhs.len() != rhs.len() { - return Err(Error::InvalidArgumentError( - "Cannot perform bitwise operation on arrays of different length".to_string(), - )); - } +pub fn or(lhs: &BooleanArray, rhs: &BooleanArray) -> BooleanArray { + assert_eq!( + lhs.len(), + rhs.len(), + "lhs and rhs must have the same length" + ); let lhs_values = lhs.values(); let rhs_values = rhs.values(); @@ -90,36 +86,29 @@ pub fn or(lhs: &BooleanArray, rhs: &BooleanArray) -> Result { } (None, None) => None, }; - Ok(BooleanArray::new( - DataType::Boolean, - lhs_values | rhs_values, - validity, - )) + BooleanArray::new(DataType::Boolean, lhs_values | rhs_values, validity) } /// Logical 'and' operation on two arrays with [Kleene logic](https://en.wikipedia.org/wiki/Three-valued_logic#Kleene_and_Priest_logics) -/// # Errors -/// This function errors if the operands have different lengths. +/// # Panics +/// This function panics iff the arrays have a different length /// # Example /// /// ```rust -/// # use arrow2::error::Result; /// use arrow2::array::BooleanArray; /// use arrow2::compute::boolean_kleene::and; -/// # fn main() -> Result<()> { +/// /// let a = BooleanArray::from(&[Some(true), Some(false), None]); /// let b = BooleanArray::from(&[None, None, None]); -/// let and_ab = and(&a, &b)?; +/// let and_ab = and(&a, &b); /// assert_eq!(and_ab, BooleanArray::from(&[None, Some(false), None])); -/// # Ok(()) -/// # } /// ``` -pub fn and(lhs: &BooleanArray, rhs: &BooleanArray) -> Result { - if lhs.len() != rhs.len() { - return Err(Error::InvalidArgumentError( - "Cannot perform bitwise operation on arrays of different length".to_string(), - )); - } +pub fn and(lhs: &BooleanArray, rhs: &BooleanArray) -> BooleanArray { + assert_eq!( + lhs.len(), + rhs.len(), + "lhs and rhs must have the same length" + ); let lhs_values = lhs.values(); let rhs_values = rhs.values(); @@ -179,11 +168,7 @@ pub fn and(lhs: &BooleanArray, rhs: &BooleanArray) -> Result { } (None, None) => None, }; - Ok(BooleanArray::new( - DataType::Boolean, - lhs_values & rhs_values, - validity, - )) + BooleanArray::new(DataType::Boolean, lhs_values & rhs_values, validity) } /// Logical 'or' operation on an array and a scalar value with [Kleene logic](https://en.wikipedia.org/wiki/Three-valued_logic#Kleene_and_Priest_logics) @@ -193,12 +178,11 @@ pub fn and(lhs: &BooleanArray, rhs: &BooleanArray) -> Result { /// use arrow2::array::BooleanArray; /// use arrow2::scalar::BooleanScalar; /// use arrow2::compute::boolean_kleene::or_scalar; -/// # fn main() { +/// /// let array = BooleanArray::from(&[Some(true), Some(false), None]); /// let scalar = BooleanScalar::new(Some(false)); /// let result = or_scalar(&array, &scalar); /// assert_eq!(result, BooleanArray::from(&[Some(true), Some(false), None])); -/// # } /// ``` pub fn or_scalar(array: &BooleanArray, scalar: &BooleanScalar) -> BooleanArray { match scalar.value() { @@ -226,12 +210,11 @@ pub fn or_scalar(array: &BooleanArray, scalar: &BooleanScalar) -> BooleanArray { /// use arrow2::array::BooleanArray; /// use arrow2::scalar::BooleanScalar; /// use arrow2::compute::boolean_kleene::and_scalar; -/// # fn main() { +/// /// let array = BooleanArray::from(&[Some(true), Some(false), None]); /// let scalar = BooleanScalar::new(None); /// let result = and_scalar(&array, &scalar); /// assert_eq!(result, BooleanArray::from(&[None, Some(false), None])); -/// # } /// ``` pub fn and_scalar(array: &BooleanArray, scalar: &BooleanScalar) -> BooleanArray { match scalar.value() { @@ -250,3 +233,25 @@ pub fn and_scalar(array: &BooleanArray, scalar: &BooleanScalar) -> BooleanArray } } } + +/// Returns whether any of the values in the array is `true` +pub fn any(array: &BooleanArray) -> bool { + if array.is_empty() { + false + } else if array.validity().is_some() { + array.into_iter().any(|v| v == Some(true)) + } else { + let vals = array.values(); + vals.unset_bits() != vals.len() + } +} + +/// Returns whether all values in the array are `true` +pub fn all(array: &BooleanArray) -> bool { + if array.is_empty() || array.null_count() > 0 { + false + } else { + let vals = array.values(); + vals.unset_bits() == 0 + } +} diff --git a/src/compute/comparison/mod.rs b/src/compute/comparison/mod.rs index 8f67856b90e..4ad7920705e 100644 --- a/src/compute/comparison/mod.rs +++ b/src/compute/comparison/mod.rs @@ -515,21 +515,20 @@ fn finish_eq_validities( (Some(lhs), None) => compute::boolean::and( &BooleanArray::new(DataType::Boolean, lhs, None), &output_without_validities, - ) - .unwrap(), + ), (None, Some(rhs)) => compute::boolean::and( &output_without_validities, &BooleanArray::new(DataType::Boolean, rhs, None), - ) - .unwrap(), + ), (Some(lhs), Some(rhs)) => { let lhs = BooleanArray::new(DataType::Boolean, lhs, None); let rhs = BooleanArray::new(DataType::Boolean, rhs, None); let eq_validities = compute::comparison::boolean::eq(&lhs, &rhs); - compute::boolean::and(&output_without_validities, &eq_validities).unwrap() + compute::boolean::and(&output_without_validities, &eq_validities) } } } + fn finish_neq_validities( output_without_validities: BooleanArray, validity_lhs: Option, @@ -540,18 +539,18 @@ fn finish_neq_validities( (Some(lhs), None) => { let lhs_negated = compute::boolean::not(&BooleanArray::new(DataType::Boolean, lhs, None)); - compute::boolean::or(&lhs_negated, &output_without_validities).unwrap() + compute::boolean::or(&lhs_negated, &output_without_validities) } (None, Some(rhs)) => { let rhs_negated = compute::boolean::not(&BooleanArray::new(DataType::Boolean, rhs, None)); - compute::boolean::or(&output_without_validities, &rhs_negated).unwrap() + compute::boolean::or(&output_without_validities, &rhs_negated) } (Some(lhs), Some(rhs)) => { let lhs = BooleanArray::new(DataType::Boolean, lhs, None); let rhs = BooleanArray::new(DataType::Boolean, rhs, None); let neq_validities = compute::comparison::boolean::neq(&lhs, &rhs); - compute::boolean::or(&output_without_validities, &neq_validities).unwrap() + compute::boolean::or(&output_without_validities, &neq_validities) } } } diff --git a/tests/it/compute/boolean.rs b/tests/it/compute/boolean.rs index fb0d1c6da31..f05d09e616b 100644 --- a/tests/it/compute/boolean.rs +++ b/tests/it/compute/boolean.rs @@ -7,7 +7,7 @@ use std::iter::FromIterator; fn array_and() { let a = BooleanArray::from_slice(vec![false, false, true, true]); let b = BooleanArray::from_slice(vec![false, true, false, true]); - let c = and(&a, &b).unwrap(); + let c = and(&a, &b); let expected = BooleanArray::from_slice(vec![false, false, false, true]); @@ -18,7 +18,7 @@ fn array_and() { fn array_or() { let a = BooleanArray::from_slice(vec![false, false, true, true]); let b = BooleanArray::from_slice(vec![false, true, false, true]); - let c = or(&a, &b).unwrap(); + let c = or(&a, &b); let expected = BooleanArray::from_slice(vec![false, true, true, true]); @@ -49,7 +49,7 @@ fn array_or_validity() { Some(false), Some(true), ]); - let c = or(&a, &b).unwrap(); + let c = or(&a, &b); let expected = BooleanArray::from(vec![ None, @@ -100,7 +100,7 @@ fn array_and_validity() { Some(false), Some(true), ]); - let c = and(&a, &b).unwrap(); + let c = and(&a, &b); let expected = BooleanArray::from(vec![ None, @@ -128,7 +128,7 @@ fn array_and_sliced_same_offset() { let a = a.slice(8, 4); let b = b.slice(8, 4); - let c = and(&a, &b).unwrap(); + let c = and(&a, &b); let expected = BooleanArray::from_slice(vec![false, false, false, true]);