Path: blob/main/crates/polars-expr/src/dispatch/horizontal.rs
7884 views
use std::borrow::Cow;12use polars_core::error::{PolarsResult, polars_bail, polars_ensure};3use polars_core::prelude::{Column, DataType, IntoColumn};4use polars_core::series::Series;5use polars_core::utils::try_get_supertype;6use polars_plan::callback::PlanCallback;78pub fn fold(9c: &[Column],10callback: &PlanCallback<(Series, Series), Series>,11returns_scalar: bool,12return_dtype: Option<&DataType>,13) -> PolarsResult<Column> {14let mut acc = c[0].clone().take_materialized_series();15let first_dtype = acc.dtype().clone();16for c in &c[1..] {17acc = callback.call((acc.clone(), c.clone().take_materialized_series()))?;18}19polars_ensure!(20!returns_scalar || acc.len() == 1,21InvalidOperation: "`fold` is said to return scalar but returned {} elements", acc.len(),22);23polars_ensure!(24return_dtype.is_none_or(|dt| dt == acc.dtype()),25ComputeError: "`fold` did not return given return_dtype ({} != {})", return_dtype.unwrap(), acc.dtype()26);2728if return_dtype.is_none() && acc.dtype() != &first_dtype {29acc = acc.cast(&first_dtype)?;30}3132Ok(acc.into_column())33}3435pub fn reduce(36c: &[Column],37callback: &PlanCallback<(Series, Series), Series>,38returns_scalar: bool,39return_dtype: Option<&DataType>,40) -> PolarsResult<Column> {41let Some(acc) = c.first() else {42polars_bail!(ComputeError: "`reduce` did not have any expressions to fold");43};4445let output_dtype = match return_dtype {46None => {47let mut supertype = acc.dtype().clone();48for c in &c[1..] {49supertype = try_get_supertype(&supertype, c.dtype())?;50}51Cow::Owned(supertype)52},53Some(dt) => Cow::Borrowed(dt),54};55let output_dtype = output_dtype.as_ref();5657let mut acc = acc.clone().take_materialized_series();58for c in &c[1..] {59acc = callback.call((acc.clone(), c.clone().take_materialized_series()))?;60}6162polars_ensure!(63!returns_scalar || acc.len() == 1,64InvalidOperation: "`reduce` is said to return scalar but returned {} elements", acc.len(),65);66polars_ensure!(67return_dtype.is_none_or(|dt| dt == acc.dtype()),68ComputeError: "`reduce` did not return given return_dtype ({} != {})", return_dtype.unwrap(), acc.dtype()69);7071if acc.dtype() != output_dtype {72acc = acc.cast(output_dtype)?;73}7475Ok(acc.into_column())76}7778#[cfg(feature = "dtype-struct")]79pub fn cum_reduce(80c: &[Column],81callback: &PlanCallback<(Series, Series), Series>,82returns_scalar: bool,83return_dtype: Option<&DataType>,84) -> PolarsResult<Column> {85use polars_core::prelude::StructChunked;8687let Some(acc) = c.first() else {88polars_bail!(ComputeError: "`cum_reduce` did not have any expressions to fold");89};9091let output_dtype = match return_dtype {92None => {93let mut supertype = acc.dtype().clone();94for c in &c[1..] {95supertype = try_get_supertype(&supertype, c.dtype())?;96}97Cow::Owned(supertype)98},99Some(dt) => Cow::Borrowed(dt),100};101let output_dtype = output_dtype.as_ref();102103let mut result = Vec::with_capacity(c.len());104let mut acc = acc.clone().take_materialized_series();105result.push(acc.clone());106for c in &c[1..] {107let name = c.name().clone();108acc = callback.call((acc.clone(), c.clone().take_materialized_series()))?;109110polars_ensure!(111!returns_scalar || acc.len() == 1,112InvalidOperation: "`cum_reduce` is said to return scalar but returned {} elements", acc.len(),113);114polars_ensure!(115return_dtype.is_none_or(|dt| dt == acc.dtype()),116ComputeError: "`cum_reduce` did not return given return_dtype ({} != {})", return_dtype.unwrap(), acc.dtype()117);118119if acc.dtype() != output_dtype {120acc = acc.cast(output_dtype)?;121}122123acc.rename(name);124result.push(acc.clone());125}126127StructChunked::from_series(acc.name().clone(), result[0].len(), result.iter())128.map(|ca| ca.into_column())129}130131#[cfg(feature = "dtype-struct")]132pub fn cum_fold(133c: &[Column],134callback: &PlanCallback<(Series, Series), Series>,135returns_scalar: bool,136return_dtype: Option<&DataType>,137include_init: bool,138) -> PolarsResult<Column> {139use polars_core::prelude::StructChunked;140141let mut result = Vec::with_capacity(c.len());142let mut acc = c[0].clone().take_materialized_series();143144let output_dtype = return_dtype.map_or_else(|| Cow::Owned(acc.dtype().clone()), Cow::Borrowed);145let output_dtype = output_dtype.as_ref();146147if include_init {148result.push(acc.clone())149}150151for c in &c[1..] {152let name = c.name().clone();153acc = callback.call((acc.clone(), c.clone().take_materialized_series()))?;154155polars_ensure!(156!returns_scalar || acc.len() == 1,157InvalidOperation: "`cum_fold` is said to return scalar but returned {} elements", acc.len(),158);159polars_ensure!(160return_dtype.is_none_or(|dt| dt == acc.dtype()),161ComputeError: "`cum_fold` did not return given return_dtype ({} != {})", return_dtype.unwrap(), acc.dtype()162);163164if acc.dtype() != output_dtype {165acc = acc.cast(output_dtype)?;166}167168acc.rename(name);169result.push(acc.clone());170}171172StructChunked::from_series(acc.name().clone(), result[0].len(), result.iter())173.map(|ca| ca.into_column())174}175176177