use arrow::array::PrimitiveArray;
use polars_arrow::prelude::FromData;
use crate::datatypes::PolarsNumericType;
use crate::prelude::*;
use crate::series::arithmetic::coerce_lhs_rhs;
use crate::utils::align_chunks_binary;
fn cmp_binary<T, F>(left: &ChunkedArray<T>, right: &ChunkedArray<T>, op: F) -> ChunkedArray<T>
where
T: PolarsNumericType,
F: Fn(T::Native, T::Native) -> T::Native,
{
let (left, right) = align_chunks_binary(left, right);
let chunks = left
.downcast_iter()
.zip(right.downcast_iter())
.map(|(left, right)| {
let values = left
.values()
.iter()
.zip(right.values().iter())
.map(|(l, r)| op(*l, *r))
.collect::<Vec<_>>();
PrimitiveArray::from_data_default(values.into(), None)
});
ChunkedArray::from_chunk_iter(left.name(), chunks)
}
fn min_binary<T>(left: &ChunkedArray<T>, right: &ChunkedArray<T>) -> ChunkedArray<T>
where
T: PolarsNumericType,
T::Native: PartialOrd,
{
let op = |l, r| {
if l < r {
l
} else {
r
}
};
cmp_binary(left, right, op)
}
fn max_binary<T>(left: &ChunkedArray<T>, right: &ChunkedArray<T>) -> ChunkedArray<T>
where
T: PolarsNumericType,
T::Native: PartialOrd,
{
let op = |l, r| {
if l > r {
l
} else {
r
}
};
cmp_binary(left, right, op)
}
pub(crate) fn min_max_binary_series(
left: &Series,
right: &Series,
min: bool,
) -> PolarsResult<Series> {
if left.dtype().to_physical().is_numeric()
&& left.null_count() == 0
&& right.null_count() == 0
&& left.len() == right.len()
{
let (lhs, rhs) = coerce_lhs_rhs(left, right)?;
let logical = lhs.dtype();
let lhs = lhs.to_physical_repr();
let rhs = rhs.to_physical_repr();
with_match_physical_numeric_polars_type!(lhs.dtype(), |$T| {
let a: &ChunkedArray<$T> = lhs.as_ref().as_ref().as_ref();
let b: &ChunkedArray<$T> = rhs.as_ref().as_ref().as_ref();
if min {
min_binary(a, b).into_series().cast(logical)
} else {
max_binary(a, b).into_series().cast(logical)
}
})
} else {
let mask = if min {
left.lt(right)? & left.is_not_null() | right.is_null()
} else {
left.gt(right)? & left.is_not_null() | right.is_null()
};
left.zip_with(&mask, right)
}
}