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