polars_core/series/implementations/
categorical.rs1use super::*;
2use crate::prelude::*;
3
4unsafe impl<T: PolarsCategoricalType> IntoSeries for CategoricalChunked<T> {
5 fn into_series(self) -> Series {
6 with_match_categorical_physical_type!(T::physical(), |$C| {
8 unsafe {
9 Series(Arc::new(SeriesWrap(core::mem::transmute::<Self, CategoricalChunked<$C>>(self))))
10 }
11 })
12 }
13}
14
15impl<T: PolarsCategoricalType> SeriesWrap<CategoricalChunked<T>> {
16 unsafe fn apply_on_phys<F>(&self, apply: F) -> CategoricalChunked<T>
17 where
18 F: FnOnce(&ChunkedArray<T::PolarsPhysical>) -> ChunkedArray<T::PolarsPhysical>,
19 {
20 let cats = apply(self.0.physical());
21 unsafe { CategoricalChunked::from_cats_and_dtype_unchecked(cats, self.0.dtype().clone()) }
22 }
23
24 unsafe fn try_apply_on_phys<F>(&self, apply: F) -> PolarsResult<CategoricalChunked<T>>
25 where
26 F: FnOnce(
27 &ChunkedArray<T::PolarsPhysical>,
28 ) -> PolarsResult<ChunkedArray<T::PolarsPhysical>>,
29 {
30 let cats = apply(self.0.physical())?;
31 unsafe {
32 Ok(CategoricalChunked::from_cats_and_dtype_unchecked(
33 cats,
34 self.0.dtype().clone(),
35 ))
36 }
37 }
38}
39
40macro_rules! impl_cat_series {
41 ($ca: ident, $pdt:ty, $ca_fn:ident) => {
42 impl private::PrivateSeries for SeriesWrap<$ca> {
43 fn compute_len(&mut self) {
44 self.0.physical_mut().compute_len()
45 }
46 fn _field(&self) -> Cow<'_, Field> {
47 Cow::Owned(self.0.field())
48 }
49 fn _dtype(&self) -> &DataType {
50 self.0.dtype()
51 }
52 fn _get_flags(&self) -> StatisticsFlags {
53 self.0.get_flags()
54 }
55 fn _set_flags(&mut self, flags: StatisticsFlags) {
56 self.0.set_flags(flags)
57 }
58
59 #[cfg(feature = "zip_with")]
60 fn zip_with_same_type(&self, mask: &BooleanChunked, other: &Series) -> PolarsResult<Series> {
61 polars_ensure!(self.dtype() == other.dtype(), SchemaMismatch: "expected '{}' found '{}'", self.dtype(), other.dtype());
62 let other = other.to_physical_repr().into_owned();
63 unsafe {
64 Ok(self.try_apply_on_phys(|ca| {
65 ca.zip_with(mask, other.as_ref().as_ref())
66 })?.into_series())
67 }
68 }
69
70 fn into_total_ord_inner<'a>(&'a self) -> Box<dyn TotalOrdInner + 'a> {
71 if self.0.uses_lexical_ordering() {
72 (&self.0).into_total_ord_inner()
73 } else {
74 self.0.physical().into_total_ord_inner()
75 }
76 }
77 fn vec_hash(
78 &self,
79 random_state: PlSeedableRandomStateQuality,
80 buf: &mut Vec<u64>,
81 ) -> PolarsResult<()> {
82 self.0.vec_hash(random_state, buf)
83 }
84
85 fn vec_hash_combine(
86 &self,
87 build_hasher: PlSeedableRandomStateQuality,
88 hashes: &mut [u64],
89 ) -> PolarsResult<()> {
90 self.0.vec_hash_combine(build_hasher, hashes)
91 }
92
93 #[cfg(feature = "algorithm_group_by")]
94 unsafe fn agg_min(&self, groups: &GroupsType) -> Series {
95 if self.0.uses_lexical_ordering() {
96 unsafe { self.0.agg_min(groups) }
97 } else {
98 self.apply_on_phys(|phys| phys.agg_min(groups).$ca_fn().unwrap().clone())
99 .into_series()
100 }
101 }
102
103 #[cfg(feature = "algorithm_group_by")]
104 unsafe fn agg_max(&self, groups: &GroupsType) -> Series {
105 if self.0.uses_lexical_ordering() {
106 unsafe { self.0.agg_max(groups) }
107 } else {
108 self.apply_on_phys(|phys| phys.agg_max(groups).$ca_fn().unwrap().clone())
109 .into_series()
110 }
111 }
112
113 #[cfg(feature = "algorithm_group_by")]
114 unsafe fn agg_arg_min(&self, groups: &GroupsType) -> Series {
115 if self.0.uses_lexical_ordering() {
116 unsafe { self.0.agg_arg_min(groups) }
117 } else {
118 self.0.physical().agg_arg_min(groups)
119 }
120 }
121
122 #[cfg(feature = "algorithm_group_by")]
123 unsafe fn agg_arg_max(&self, groups: &GroupsType) -> Series {
124 if self.0.uses_lexical_ordering() {
125 unsafe { self.0.agg_arg_max(groups) }
126 } else {
127 self.0.physical().agg_arg_max(groups)
128 }
129 }
130
131
132 #[cfg(feature = "algorithm_group_by")]
133 unsafe fn agg_list(&self, groups: &GroupsType) -> Series {
134 let list = self.0.physical().agg_list(groups);
136 let mut list = list.list().unwrap().clone();
137 unsafe { list.to_logical(self.dtype().clone()) };
138 list.into_series()
139 }
140
141 #[cfg(feature = "algorithm_group_by")]
142 fn group_tuples(&self, multithreaded: bool, sorted: bool) -> PolarsResult<GroupsType> {
143 self.0.physical().group_tuples(multithreaded, sorted)
144 }
145
146 fn arg_sort_multiple(
147 &self,
148 by: &[Column],
149 options: &SortMultipleOptions,
150 ) -> PolarsResult<IdxCa> {
151 self.0.arg_sort_multiple(by, options)
152 }
153 }
154
155 impl SeriesTrait for SeriesWrap<$ca> {
156 fn rename(&mut self, name: PlSmallStr) {
157 self.0.physical_mut().rename(name);
158 }
159
160 fn chunk_lengths(&self) -> ChunkLenIter<'_> {
161 self.0.physical().chunk_lengths()
162 }
163
164 fn name(&self) -> &PlSmallStr {
165 self.0.physical().name()
166 }
167
168 fn chunks(&self) -> &Vec<ArrayRef> {
169 self.0.physical().chunks()
170 }
171
172 unsafe fn chunks_mut(&mut self) -> &mut Vec<ArrayRef> {
173 self.0.physical_mut().chunks_mut()
174 }
175
176 fn shrink_to_fit(&mut self) {
177 self.0.physical_mut().shrink_to_fit()
178 }
179
180 fn slice(&self, offset: i64, length: usize) -> Series {
181 unsafe { self.apply_on_phys(|cats| cats.slice(offset, length)).into_series() }
182 }
183
184 fn split_at(&self, offset: i64) -> (Series, Series) {
185 unsafe {
186 let (a, b) = self.0.physical().split_at(offset);
187 let a = <$ca>::from_cats_and_dtype_unchecked(a, self.0.dtype().clone()).into_series();
188 let b = <$ca>::from_cats_and_dtype_unchecked(b, self.0.dtype().clone()).into_series();
189 (a, b)
190 }
191 }
192
193 fn append(&mut self, other: &Series) -> PolarsResult<()> {
194 polars_ensure!(self.0.dtype() == other.dtype(), append);
195 self.0.append(other.cat::<$pdt>().unwrap())
196 }
197
198 fn append_owned(&mut self, mut other: Series) -> PolarsResult<()> {
199 polars_ensure!(self.0.dtype() == other.dtype(), append);
200 self.0.physical_mut().append_owned(std::mem::take(
201 other
202 ._get_inner_mut()
203 .as_any_mut()
204 .downcast_mut::<$ca>()
205 .unwrap()
206 .physical_mut(),
207 ))
208 }
209
210 fn extend(&mut self, other: &Series) -> PolarsResult<()> {
211 polars_ensure!(self.0.dtype() == other.dtype(), extend);
212 self.0.extend(other.cat::<$pdt>().unwrap())
213 }
214
215 fn filter(&self, filter: &BooleanChunked) -> PolarsResult<Series> {
216 unsafe { Ok(self.try_apply_on_phys(|cats| cats.filter(filter))?.into_series()) }
217 }
218
219 fn take(&self, indices: &IdxCa) -> PolarsResult<Series> {
220 unsafe { Ok(self.try_apply_on_phys(|cats| cats.take(indices))?.into_series() ) }
221 }
222
223 unsafe fn take_unchecked(&self, indices: &IdxCa) -> Series {
224 unsafe { self.apply_on_phys(|cats| cats.take_unchecked(indices)).into_series() }
225 }
226
227 fn take_slice(&self, indices: &[IdxSize]) -> PolarsResult<Series> {
228 unsafe { Ok(self.try_apply_on_phys(|cats| cats.take(indices))?.into_series()) }
229 }
230
231 unsafe fn take_slice_unchecked(&self, indices: &[IdxSize]) -> Series {
232 unsafe { self.apply_on_phys(|cats| cats.take_unchecked(indices)).into_series() }
233 }
234
235 fn deposit(&self, validity: &Bitmap) -> Series {
236 unsafe { self.apply_on_phys(|cats| cats.deposit(validity)) }
237 .into_series()
238 }
239
240 fn len(&self) -> usize {
241 self.0.len()
242 }
243
244 fn rechunk(&self) -> Series {
245 unsafe { self.apply_on_phys(|cats| cats.rechunk().into_owned()).into_series() }
246 }
247
248 fn with_validity(&self, validity: Option<Bitmap>) -> Series {
249 unsafe { self.apply_on_phys(move |cats| cats.clone().with_validity(validity)).into_series() }
250 }
251
252 fn new_from_index(&self, index: usize, length: usize) -> Series {
253 unsafe { self.apply_on_phys(|cats| cats.new_from_index(index, length)).into_series() }
254 }
255
256 fn cast(&self, dtype: &DataType, options: CastOptions) -> PolarsResult<Series> {
257 self.0.cast_with_options(dtype, options)
258 }
259
260 #[inline]
261 unsafe fn get_unchecked(&self, index: usize) -> AnyValue<'_> {
262 self.0.get_any_value_unchecked(index)
263 }
264
265 fn sort_with(&self, options: SortOptions) -> PolarsResult<Series> {
266 Ok(self.0.sort_with(options).into_series())
267 }
268
269 fn arg_sort(&self, options: SortOptions) -> IdxCa {
270 self.0.arg_sort(options)
271 }
272
273 fn null_count(&self) -> usize {
274 self.0.physical().null_count()
275 }
276
277 fn has_nulls(&self) -> bool {
278 self.0.physical().has_nulls()
279 }
280
281 #[cfg(feature = "algorithm_group_by")]
282 fn unique(&self) -> PolarsResult<Series> {
283 unsafe { Ok(self.try_apply_on_phys(|cats| cats.unique())?.into_series()) }
284 }
285
286 #[cfg(feature = "algorithm_group_by")]
287 fn n_unique(&self) -> PolarsResult<usize> {
288 self.0.physical().n_unique()
289 }
290
291 #[cfg(feature = "approx_unique")]
292 fn approx_n_unique(&self) -> PolarsResult<IdxSize> {
293 Ok(self.0.physical().approx_n_unique())
294 }
295
296 #[cfg(feature = "algorithm_group_by")]
297 fn arg_unique(&self) -> PolarsResult<IdxCa> {
298 self.0.physical().arg_unique()
299 }
300
301 #[cfg(feature = "algorithm_group_by")]
302 fn unique_id(&self) -> PolarsResult<(IdxSize, Vec<IdxSize>)> {
303 ChunkUnique::unique_id(self.0.physical())
304 }
305
306 fn is_null(&self) -> BooleanChunked {
307 self.0.physical().is_null()
308 }
309
310 fn is_not_null(&self) -> BooleanChunked {
311 self.0.physical().is_not_null()
312 }
313
314 fn reverse(&self) -> Series {
315 unsafe { self.apply_on_phys(|cats| cats.reverse()).into_series() }
316 }
317
318 fn as_single_ptr(&mut self) -> PolarsResult<usize> {
319 self.0.physical_mut().as_single_ptr()
320 }
321
322 fn shift(&self, periods: i64) -> Series {
323 unsafe { self.apply_on_phys(|ca| ca.shift(periods)).into_series() }
324 }
325
326 fn clone_inner(&self) -> Arc<dyn SeriesTrait> {
327 Arc::new(SeriesWrap(Clone::clone(&self.0)))
328 }
329
330 fn min_reduce(&self) -> PolarsResult<Scalar> {
331 Ok(ChunkAggSeries::min_reduce(&self.0))
332 }
333
334 fn max_reduce(&self) -> PolarsResult<Scalar> {
335 Ok(ChunkAggSeries::max_reduce(&self.0))
336 }
337
338 fn find_validity_mismatch(&self, other: &Series, idxs: &mut Vec<IdxSize>) {
339 self.0.physical().find_validity_mismatch(other, idxs)
340 }
341
342 fn as_any(&self) -> &dyn Any {
343 &self.0
344 }
345
346 fn as_any_mut(&mut self) -> &mut dyn Any {
347 &mut self.0
348 }
349
350 fn as_phys_any(&self) -> &dyn Any {
351 self.0.physical()
352 }
353
354 fn as_arc_any(self: Arc<Self>) -> Arc<dyn Any + Send + Sync> {
355 self as _
356 }
357 }
358
359 impl private::PrivateSeriesNumeric for SeriesWrap<$ca> {
360 fn bit_repr(&self) -> Option<BitRepr> {
361 Some(self.0.physical().to_bit_repr())
362 }
363 }
364 }
365}
366
367impl_cat_series!(Categorical8Chunked, Categorical8Type, u8);
368impl_cat_series!(Categorical16Chunked, Categorical16Type, u16);
369impl_cat_series!(Categorical32Chunked, Categorical32Type, u32);