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