polars_core/chunked_array/ops/
reverse.rs1#[cfg(feature = "dtype-array")]
2use crate::chunked_array::builder::get_fixed_size_list_builder;
3use crate::prelude::*;
4use crate::series::IsSorted;
5use crate::utils::NoNull;
6
7impl<T> ChunkReverse for ChunkedArray<T>
8where
9 T: PolarsNumericType,
10{
11 fn reverse(&self) -> ChunkedArray<T> {
12 let mut out = if let Ok(slice) = self.cont_slice() {
13 let ca: NoNull<ChunkedArray<T>> = slice.iter().rev().copied().collect_trusted();
14 ca.into_inner()
15 } else {
16 self.into_iter().rev().collect_trusted()
17 };
18 out.rename(self.name().clone());
19
20 match self.is_sorted_flag() {
21 IsSorted::Ascending => out.set_sorted_flag(IsSorted::Descending),
22 IsSorted::Descending => out.set_sorted_flag(IsSorted::Ascending),
23 _ => {},
24 }
25
26 out
27 }
28}
29
30macro_rules! impl_reverse {
31 ($arrow_type:ident, $ca_type:ident) => {
32 impl ChunkReverse for $ca_type {
33 fn reverse(&self) -> Self {
34 if self.is_empty() {
35 return self.clone();
36 };
37 let mut ca: Self = self.into_iter().rev().collect_trusted();
38 ca.rename(self.name().clone());
39 ca
40 }
41 }
42 };
43}
44
45impl_reverse!(BooleanType, BooleanChunked);
46impl_reverse!(BinaryOffsetType, BinaryOffsetChunked);
47impl_reverse!(ListType, ListChunked);
48
49impl ChunkReverse for BinaryChunked {
50 fn reverse(&self) -> Self {
51 if self.chunks.len() == 1 {
52 let arr = self.downcast_iter().next().unwrap();
53 let views = arr.views().iter().copied().rev().collect::<Vec<_>>();
54
55 unsafe {
56 let arr = BinaryViewArray::new_unchecked(
57 arr.dtype().clone(),
58 views.into(),
59 arr.data_buffers().clone(),
60 arr.validity().map(|bitmap| bitmap.iter().rev().collect()),
61 arr.total_bytes_len(),
62 arr.total_buffer_len(),
63 )
64 .boxed();
65 BinaryChunked::from_chunks_and_dtype_unchecked(
66 self.name().clone(),
67 vec![arr],
68 self.dtype().clone(),
69 )
70 }
71 } else {
72 let ca = IdxCa::from_vec(
73 PlSmallStr::EMPTY,
74 (0..self.len() as IdxSize).rev().collect(),
75 );
76 unsafe { self.take_unchecked(&ca) }
77 }
78 }
79}
80
81impl ChunkReverse for StringChunked {
82 fn reverse(&self) -> Self {
83 unsafe { self.as_binary().reverse().to_string_unchecked() }
84 }
85}
86
87#[cfg(feature = "dtype-array")]
88impl ChunkReverse for ArrayChunked {
89 fn reverse(&self) -> Self {
90 if !self.inner_dtype().is_primitive_numeric() {
91 todo!("reverse for FixedSizeList with non-numeric dtypes not yet supported")
92 }
93 let ca = self.rechunk();
94 let arr = ca.downcast_as_array();
95 let values = arr.values().as_ref();
96
97 let mut builder =
98 get_fixed_size_list_builder(ca.inner_dtype(), ca.len(), ca.width(), ca.name().clone())
99 .expect("not yet supported");
100
101 unsafe {
103 if arr.null_count() == 0 {
104 for i in (0..arr.len()).rev() {
105 builder.push_unchecked(values, i)
106 }
107 } else {
108 let validity = arr.validity().unwrap();
109 for i in (0..arr.len()).rev() {
110 if validity.get_bit_unchecked(i) {
111 builder.push_unchecked(values, i)
112 } else {
113 builder.push_null()
114 }
115 }
116 }
117 }
118 builder.finish()
119 }
120}
121
122#[cfg(feature = "object")]
123impl<T: PolarsObject> ChunkReverse for ObjectChunked<T> {
124 fn reverse(&self) -> Self {
125 unsafe {
127 self.take_unchecked(
128 &(0..self.len() as IdxSize)
129 .rev()
130 .collect_ca(PlSmallStr::EMPTY),
131 )
132 }
133 }
134}