polars_core/chunked_array/ops/
append.rs1use polars_error::constants::LENGTH_LIMIT_MSG;
2
3use crate::prelude::*;
4use crate::series::IsSorted;
5
6pub(crate) fn new_chunks(chunks: &mut Vec<ArrayRef>, other: &[ArrayRef], len: usize) {
7 if chunks.len() == 1 && len == 0 {
9 other.clone_into(chunks);
10 } else {
11 for chunk in other {
12 if !chunk.is_empty() {
13 chunks.push(chunk.clone());
14 }
15 }
16 }
17}
18
19pub(crate) fn new_chunks_owned(chunks: &mut Vec<ArrayRef>, other: Vec<ArrayRef>, len: usize) {
20 if chunks.len() == 1 && len == 0 {
22 *chunks = other;
23 } else {
24 chunks.reserve(other.len());
25 chunks.extend(other.into_iter().filter(|c| !c.is_empty()));
26 }
27}
28
29pub(super) fn update_sorted_flag_before_append<T>(ca: &mut ChunkedArray<T>, other: &ChunkedArray<T>)
30where
31 T: PolarsDataType,
32 for<'a> T::Physical<'a>: TotalOrd,
33{
34 let sorted_flag = match (
37 ca.null_count() != ca.len(),
38 other.null_count() != other.len(),
39 ) {
40 (false, false) => IsSorted::Ascending,
41 (false, true) => {
42 if
43 ca.is_empty()
45 || (
46 other.is_sorted_any() && 1 + other.last_non_null().unwrap() == other.len()
48 )
49 {
50 other.is_sorted_flag()
51 } else {
52 IsSorted::Not
53 }
54 },
55 (true, false) => {
56 if
57 other.is_empty()
59 || (
60 ca.is_sorted_any() && ca.first_non_null().unwrap() == 0
62 )
63 {
64 ca.is_sorted_flag()
65 } else {
66 IsSorted::Not
67 }
68 },
69 (true, true) => {
70 if !(ca.is_sorted_any() || ca.len() == 1)
74 || !(other.is_sorted_any() || other.len() == 1)
75 || !(
76 ca.len() - ca.null_count() == 1
78 || other.len() - other.null_count() == 1
79 || ca.is_sorted_flag() == other.is_sorted_flag()
80 )
81 {
82 IsSorted::Not
83 } else {
84 let l_idx = ca.last_non_null().unwrap();
85 let r_idx = other.first_non_null().unwrap();
86
87 let null_pos_check =
88 (1 + l_idx == ca.len())
91 && (r_idx == 0)
93 && !(ca.first_non_null().unwrap() != 0 && 1 + other.last_non_null().unwrap() != other.len());
95
96 if !null_pos_check {
97 IsSorted::Not
98 } else {
99 #[allow(unused_assignments)]
100 let mut out = IsSorted::Not;
101
102 let l_val = unsafe { ca.value_unchecked(l_idx) };
104 let r_val = unsafe { other.value_unchecked(r_idx) };
105
106 match (
107 ca.len() - ca.null_count() == 1,
108 other.len() - other.null_count() == 1,
109 ) {
110 (true, true) => {
111 out = [IsSorted::Descending, IsSorted::Ascending]
112 [l_val.tot_le(&r_val) as usize];
113 drop(l_val);
114 drop(r_val);
115 ca.set_sorted_flag(out);
116 return;
117 },
118 (true, false) => out = other.is_sorted_flag(),
119 _ => out = ca.is_sorted_flag(),
120 }
121
122 debug_assert!(!matches!(out, IsSorted::Not));
123
124 let check = if matches!(out, IsSorted::Ascending) {
125 l_val.tot_le(&r_val)
126 } else {
127 l_val.tot_ge(&r_val)
128 };
129
130 if !check {
131 out = IsSorted::Not
132 }
133
134 out
135 }
136 }
137 },
138 };
139
140 ca.set_sorted_flag(sorted_flag);
141}
142
143impl<T> ChunkedArray<T>
144where
145 T: PolarsDataType<IsNested = FalseT, IsObject = FalseT>,
146 for<'a> T::Physical<'a>: TotalOrd,
147{
148 pub fn append(&mut self, other: &Self) -> PolarsResult<()> {
152 self.append_owned(other.clone())
153 }
154
155 pub fn append_owned(&mut self, mut other: Self) -> PolarsResult<()> {
159 update_sorted_flag_before_append::<T>(self, &other);
160 let len = self.len();
161 self.length = self
162 .length
163 .checked_add(other.length)
164 .ok_or_else(|| polars_err!(ComputeError: LENGTH_LIMIT_MSG))?;
165 self.null_count += other.null_count;
166 new_chunks_owned(&mut self.chunks, std::mem::take(&mut other.chunks), len);
167 Ok(())
168 }
169}
170
171#[doc(hidden)]
172impl ListChunked {
173 pub fn append(&mut self, other: &Self) -> PolarsResult<()> {
174 self.append_owned(other.clone())
175 }
176
177 pub fn append_owned(&mut self, mut other: Self) -> PolarsResult<()> {
178 let dtype = merge_dtypes(self.dtype(), other.dtype())?;
179 self.field = Arc::new(Field::new(self.name().clone(), dtype));
180
181 let len = self.len();
182 self.length = self
183 .length
184 .checked_add(other.length)
185 .ok_or_else(|| polars_err!(ComputeError: LENGTH_LIMIT_MSG))?;
186 self.null_count += other.null_count;
187 self.set_sorted_flag(IsSorted::Not);
188 if !other.get_fast_explode_list() {
189 self.unset_fast_explode_list()
190 }
191
192 new_chunks_owned(&mut self.chunks, std::mem::take(&mut other.chunks), len);
193 Ok(())
194 }
195}
196
197#[cfg(feature = "dtype-array")]
198#[doc(hidden)]
199impl ArrayChunked {
200 pub fn append(&mut self, other: &Self) -> PolarsResult<()> {
201 self.append_owned(other.clone())
202 }
203
204 pub fn append_owned(&mut self, mut other: Self) -> PolarsResult<()> {
205 let dtype = merge_dtypes(self.dtype(), other.dtype())?;
206 self.field = Arc::new(Field::new(self.name().clone(), dtype));
207
208 let len = self.len();
209
210 self.length = self
211 .length
212 .checked_add(other.length)
213 .ok_or_else(|| polars_err!(ComputeError: LENGTH_LIMIT_MSG))?;
214 self.null_count += other.null_count;
215
216 self.set_sorted_flag(IsSorted::Not);
217
218 new_chunks_owned(&mut self.chunks, std::mem::take(&mut other.chunks), len);
219 Ok(())
220 }
221}
222
223#[cfg(feature = "dtype-struct")]
224#[doc(hidden)]
225impl StructChunked {
226 pub fn append(&mut self, other: &Self) -> PolarsResult<()> {
227 self.append_owned(other.clone())
228 }
229
230 pub fn append_owned(&mut self, mut other: Self) -> PolarsResult<()> {
231 let dtype = merge_dtypes(self.dtype(), other.dtype())?;
232 self.field = Arc::new(Field::new(self.name().clone(), dtype));
233
234 let len = self.len();
235
236 self.length = self
237 .length
238 .checked_add(other.length)
239 .ok_or_else(|| polars_err!(ComputeError: LENGTH_LIMIT_MSG))?;
240 self.null_count += other.null_count;
241
242 self.set_sorted_flag(IsSorted::Not);
243
244 new_chunks_owned(&mut self.chunks, std::mem::take(&mut other.chunks), len);
245 Ok(())
246 }
247}
248
249#[cfg(feature = "object")]
250#[doc(hidden)]
251impl<T: PolarsObject> ObjectChunked<T> {
252 pub fn append(&mut self, other: &Self) -> PolarsResult<()> {
253 self.append_owned(other.clone())
254 }
255
256 pub fn append_owned(&mut self, mut other: Self) -> PolarsResult<()> {
257 let len = self.len();
258 self.length = self
259 .length
260 .checked_add(other.length)
261 .ok_or_else(|| polars_err!(ComputeError: LENGTH_LIMIT_MSG))?;
262 self.null_count += other.null_count;
263 self.set_sorted_flag(IsSorted::Not);
264
265 new_chunks_owned(&mut self.chunks, std::mem::take(&mut other.chunks), len);
266 Ok(())
267 }
268}