polars_python/expr/
list.rs1use std::borrow::Cow;
2
3use polars::prelude::*;
4use polars::series::ops::NullBehavior;
5use polars_utils::pl_str::PlSmallStr;
6use pyo3::prelude::*;
7use pyo3::types::PySequence;
8
9use crate::PyExpr;
10use crate::conversion::Wrap;
11
12#[pymethods]
13impl PyExpr {
14 #[cfg(feature = "list_any_all")]
15 fn list_all(&self) -> Self {
16 self.inner.clone().list().all().into()
17 }
18
19 #[cfg(feature = "list_any_all")]
20 fn list_any(&self) -> Self {
21 self.inner.clone().list().any().into()
22 }
23
24 fn list_arg_max(&self) -> Self {
25 self.inner.clone().list().arg_max().into()
26 }
27
28 fn list_arg_min(&self) -> Self {
29 self.inner.clone().list().arg_min().into()
30 }
31
32 #[cfg(feature = "is_in")]
33 fn list_contains(&self, other: PyExpr, nulls_equal: bool) -> Self {
34 self.inner
35 .clone()
36 .list()
37 .contains(other.inner, nulls_equal)
38 .into()
39 }
40
41 #[cfg(feature = "list_count")]
42 fn list_count_matches(&self, expr: PyExpr) -> Self {
43 self.inner.clone().list().count_matches(expr.inner).into()
44 }
45
46 fn list_diff(&self, n: i64, null_behavior: Wrap<NullBehavior>) -> PyResult<Self> {
47 Ok(self.inner.clone().list().diff(n, null_behavior.0).into())
48 }
49
50 fn list_eval(&self, expr: PyExpr, parallel: bool) -> Self {
51 self.inner.clone().list().eval(expr.inner, parallel).into()
52 }
53
54 #[cfg(feature = "list_filter")]
55 fn list_filter(&self, predicate: PyExpr) -> Self {
56 self.inner
57 .clone()
58 .list()
59 .eval(
60 Expr::Column(PlSmallStr::EMPTY).filter(predicate.inner),
61 false,
62 )
63 .into()
64 }
65
66 fn list_get(&self, index: PyExpr, null_on_oob: bool) -> Self {
67 self.inner
68 .clone()
69 .list()
70 .get(index.inner, null_on_oob)
71 .into()
72 }
73
74 fn list_join(&self, separator: PyExpr, ignore_nulls: bool) -> Self {
75 self.inner
76 .clone()
77 .list()
78 .join(separator.inner, ignore_nulls)
79 .into()
80 }
81
82 fn list_len(&self) -> Self {
83 self.inner.clone().list().len().into()
84 }
85
86 fn list_max(&self) -> Self {
87 self.inner.clone().list().max().into()
88 }
89
90 fn list_mean(&self) -> Self {
91 self.inner
92 .clone()
93 .list()
94 .mean()
95 .with_fmt("list.mean")
96 .into()
97 }
98
99 fn list_median(&self) -> Self {
100 self.inner
101 .clone()
102 .list()
103 .median()
104 .with_fmt("list.median")
105 .into()
106 }
107
108 fn list_std(&self, ddof: u8) -> Self {
109 self.inner
110 .clone()
111 .list()
112 .std(ddof)
113 .with_fmt("list.std")
114 .into()
115 }
116
117 fn list_var(&self, ddof: u8) -> Self {
118 self.inner
119 .clone()
120 .list()
121 .var(ddof)
122 .with_fmt("list.var")
123 .into()
124 }
125
126 fn list_min(&self) -> Self {
127 self.inner.clone().list().min().into()
128 }
129
130 fn list_reverse(&self) -> Self {
131 self.inner.clone().list().reverse().into()
132 }
133
134 fn list_shift(&self, periods: PyExpr) -> Self {
135 self.inner.clone().list().shift(periods.inner).into()
136 }
137
138 #[pyo3(signature = (offset, length=None))]
139 fn list_slice(&self, offset: PyExpr, length: Option<PyExpr>) -> Self {
140 let length = match length {
141 Some(i) => i.inner,
142 None => lit(i64::MAX),
143 };
144 self.inner.clone().list().slice(offset.inner, length).into()
145 }
146
147 fn list_tail(&self, n: PyExpr) -> Self {
148 self.inner.clone().list().tail(n.inner).into()
149 }
150
151 fn list_sort(&self, descending: bool, nulls_last: bool) -> Self {
152 self.inner
153 .clone()
154 .list()
155 .sort(
156 SortOptions::default()
157 .with_order_descending(descending)
158 .with_nulls_last(nulls_last),
159 )
160 .into()
161 }
162
163 fn list_sum(&self) -> Self {
164 self.inner.clone().list().sum().with_fmt("list.sum").into()
165 }
166
167 #[cfg(feature = "list_drop_nulls")]
168 fn list_drop_nulls(&self) -> Self {
169 self.inner.clone().list().drop_nulls().into()
170 }
171
172 #[cfg(feature = "list_sample")]
173 #[pyo3(signature = (n, with_replacement, shuffle, seed=None))]
174 fn list_sample_n(
175 &self,
176 n: PyExpr,
177 with_replacement: bool,
178 shuffle: bool,
179 seed: Option<u64>,
180 ) -> Self {
181 self.inner
182 .clone()
183 .list()
184 .sample_n(n.inner, with_replacement, shuffle, seed)
185 .into()
186 }
187
188 #[cfg(feature = "list_sample")]
189 #[pyo3(signature = (fraction, with_replacement, shuffle, seed=None))]
190 fn list_sample_fraction(
191 &self,
192 fraction: PyExpr,
193 with_replacement: bool,
194 shuffle: bool,
195 seed: Option<u64>,
196 ) -> Self {
197 self.inner
198 .clone()
199 .list()
200 .sample_fraction(fraction.inner, with_replacement, shuffle, seed)
201 .into()
202 }
203
204 #[cfg(feature = "list_gather")]
205 fn list_gather(&self, index: PyExpr, null_on_oob: bool) -> Self {
206 self.inner
207 .clone()
208 .list()
209 .gather(index.inner, null_on_oob)
210 .into()
211 }
212
213 #[cfg(feature = "list_gather")]
214 fn list_gather_every(&self, n: PyExpr, offset: PyExpr) -> Self {
215 self.inner
216 .clone()
217 .list()
218 .gather_every(n.inner, offset.inner)
219 .into()
220 }
221
222 fn list_to_array(&self, width: usize) -> Self {
223 self.inner.clone().list().to_array(width).into()
224 }
225
226 #[pyo3(signature = (width_strat, name_gen, upper_bound))]
227 fn list_to_struct(
228 &self,
229 width_strat: Wrap<ListToStructWidthStrategy>,
230 name_gen: Option<PyObject>,
231 upper_bound: Option<usize>,
232 ) -> PyResult<Self> {
233 let name_gen = name_gen.map(|lambda| {
234 NameGenerator::from_func(move |idx: usize| {
235 Python::with_gil(|py| {
236 let out = lambda.call1(py, (idx,)).unwrap();
237 let out: PlSmallStr = out.extract::<Cow<str>>(py).unwrap().as_ref().into();
238 out
239 })
240 })
241 });
242
243 Ok(self
244 .inner
245 .clone()
246 .list()
247 .to_struct(ListToStructArgs::InferWidth {
248 infer_field_strategy: width_strat.0,
249 get_index_name: name_gen,
250 max_fields: upper_bound,
251 })
252 .into())
253 }
254
255 #[pyo3(signature = (names))]
256 fn list_to_struct_fixed_width(&self, names: Bound<'_, PySequence>) -> PyResult<Self> {
257 Ok(self
258 .inner
259 .clone()
260 .list()
261 .to_struct(ListToStructArgs::FixedWidth(
262 names
263 .try_iter()?
264 .map(|x| Ok(x?.extract::<Wrap<PlSmallStr>>()?.0))
265 .collect::<PyResult<Arc<[_]>>>()?,
266 ))
267 .into())
268 }
269
270 fn list_n_unique(&self) -> Self {
271 self.inner.clone().list().n_unique().into()
272 }
273
274 fn list_unique(&self, maintain_order: bool) -> Self {
275 let e = self.inner.clone();
276
277 if maintain_order {
278 e.list().unique_stable().into()
279 } else {
280 e.list().unique().into()
281 }
282 }
283
284 #[cfg(feature = "list_sets")]
285 fn list_set_operation(&self, other: PyExpr, operation: Wrap<SetOperation>) -> Self {
286 let e = self.inner.clone().list();
287 match operation.0 {
288 SetOperation::Intersection => e.set_intersection(other.inner),
289 SetOperation::Difference => e.set_difference(other.inner),
290 SetOperation::Union => e.union(other.inner),
291 SetOperation::SymmetricDifference => e.set_symmetric_difference(other.inner),
292 }
293 .into()
294 }
295}