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