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.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.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);
47
48impl ChunkReverse for ListChunked {
49 fn reverse(&self) -> Self {
50 if self.is_empty() {
51 return self.clone();
52 };
53 let ca: Self = self.series_iter().rev().collect_trusted();
54 ca.with_name(self.name().clone())
55 }
56}
57
58impl ChunkReverse for BinaryChunked {
59 fn reverse(&self) -> Self {
60 if self.chunks.len() == 1 {
61 let arr = self.downcast_iter().next().unwrap();
62 let views = arr.views().iter().copied().rev().collect::<Vec<_>>();
63
64 unsafe {
65 let arr = BinaryViewArray::new_unchecked(
66 arr.dtype().clone(),
67 views.into(),
68 arr.data_buffers().clone(),
69 arr.validity().map(|bitmap| bitmap.iter().rev().collect()),
70 arr.try_total_bytes_len(),
71 arr.total_buffer_len(),
72 )
73 .boxed();
74 BinaryChunked::from_chunks_and_dtype_unchecked(
75 self.name().clone(),
76 vec![arr],
77 self.dtype().clone(),
78 )
79 }
80 } else {
81 let ca = IdxCa::from_vec(
82 PlSmallStr::EMPTY,
83 (0..self.len() as IdxSize).rev().collect(),
84 );
85 unsafe { self.take_unchecked(&ca) }
86 }
87 }
88}
89
90impl ChunkReverse for StringChunked {
91 fn reverse(&self) -> Self {
92 unsafe { self.as_binary().reverse().to_string_unchecked() }
93 }
94}
95
96#[cfg(feature = "dtype-array")]
97impl ChunkReverse for ArrayChunked {
98 fn reverse(&self) -> Self {
99 if !self.inner_dtype().is_primitive_numeric() {
100 todo!("reverse for FixedSizeList with non-numeric dtypes not yet supported")
101 }
102 let ca = self.rechunk();
103 let arr = ca.downcast_as_array();
104 let values = arr.values().as_ref();
105
106 let mut builder =
107 get_fixed_size_list_builder(ca.inner_dtype(), ca.len(), ca.width(), ca.name().clone())
108 .expect("not yet supported");
109
110 unsafe {
112 if arr.null_count() == 0 {
113 for i in (0..arr.len()).rev() {
114 builder.push_unchecked(values, i)
115 }
116 } else {
117 let validity = arr.validity().unwrap();
118 for i in (0..arr.len()).rev() {
119 if validity.get_bit_unchecked(i) {
120 builder.push_unchecked(values, i)
121 } else {
122 builder.push_null()
123 }
124 }
125 }
126 }
127 builder.finish()
128 }
129}
130
131#[cfg(feature = "object")]
132impl<T: PolarsObject> ChunkReverse for ObjectChunked<T> {
133 fn reverse(&self) -> Self {
134 unsafe {
136 self.take_unchecked(
137 &(0..self.len() as IdxSize)
138 .rev()
139 .collect_ca(PlSmallStr::EMPTY),
140 )
141 }
142 }
143}