#[cfg(feature = "dtype-struct")]
use polars_core::prelude::sort::arg_sort_multiple::_get_rows_encoded_ca;
use polars_core::prelude::*;
use polars_core::series::IsSorted;
use crate::series::ops::SeriesSealed;
pub trait SeriesMethods: SeriesSealed {
fn value_counts(&self, sort: bool, parallel: bool) -> PolarsResult<DataFrame> {
let s = self.as_series();
polars_ensure!(
s.name() != "count",
Duplicate: "using `value_counts` on a column named 'count' would lead to duplicate column names"
);
let groups = s.group_tuples(parallel, sort)?;
let values = unsafe { s.agg_first(&groups) };
let counts = groups.group_lengths("count");
let cols = vec![values, counts.into_series()];
let df = unsafe { DataFrame::new_no_checks(cols) };
if sort {
df.sort(
["count"],
SortMultipleOptions::default()
.with_order_descending(true)
.with_multithreaded(parallel),
)
} else {
Ok(df)
}
}
#[cfg(feature = "hash")]
fn hash(&self, build_hasher: ahash::RandomState) -> UInt64Chunked {
let s = self.as_series().to_physical_repr();
match s.dtype() {
DataType::List(_) => {
let mut ca = s.list().unwrap().clone();
crate::chunked_array::hash::hash(&mut ca, build_hasher)
},
_ => {
let mut h = vec![];
s.0.vec_hash(build_hasher, &mut h).unwrap();
UInt64Chunked::from_vec(s.name(), h)
},
}
}
fn is_sorted(&self, options: SortOptions) -> PolarsResult<bool> {
let s = self.as_series();
#[cfg(feature = "dtype-struct")]
if matches!(s.dtype(), DataType::Struct(_)) {
let encoded =
_get_rows_encoded_ca("", &[s.clone()], &[options.descending], options.nulls_last)?;
return encoded.into_series().is_sorted(options);
}
if (options.descending
&& options.nulls_last
&& matches!(s.is_sorted_flag(), IsSorted::Descending))
|| (!options.descending
&& !options.nulls_last
&& matches!(s.is_sorted_flag(), IsSorted::Ascending))
{
return Ok(true);
}
let nc = s.null_count();
let slen = s.len() - nc - 1; if nc == s.len() {
return Ok(true);
}
if nc > 0 {
let nulls = s.chunks().iter().flat_map(|c| c.validity().unwrap());
let mut npairs = nulls.clone().zip(nulls.skip(1));
if (options.nulls_last && npairs.any(|(a, b)| !a && b)) || npairs.any(|(a, b)| a && !b)
{
return Ok(false);
}
}
let offset = !options.nulls_last as i64 * nc as i64;
let (s1, s2) = (s.slice(offset, slen), s.slice(offset + 1, slen));
let cmp_op = if options.descending {
Series::gt_eq
} else {
Series::lt_eq
};
Ok(cmp_op(&s1, &s2)?.all())
}
}
impl SeriesMethods for Series {}