Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
pola-rs
GitHub Repository: pola-rs/polars
Path: blob/main/crates/polars-expr/src/dispatch/range/utils.rs
7884 views
1
use polars_core::prelude::{
2
ChunkedArray, Column, Int64Chunked, IntoColumn, ListBuilderTrait, ListPrimitiveChunkedBuilder,
3
PolarsIntegerType, PolarsNumericType, PolarsResult, polars_bail, polars_ensure,
4
};
5
6
pub(super) fn temporal_series_to_i64_scalar(s: &Column) -> Option<i64> {
7
s.to_physical_repr().get(0).unwrap().extract::<i64>()
8
}
9
pub(super) fn ensure_items_contain_exactly_one_value(
10
values: &[&Column],
11
names: &[&str],
12
) -> PolarsResult<()> {
13
for (value, name) in values.iter().zip(names.iter()) {
14
polars_ensure!(
15
value.len() == 1,
16
ComputeError: "`{name}` must contain exactly one value, got {} values", value.len()
17
)
18
}
19
Ok(())
20
}
21
22
/// Create a numeric ranges column from the given start/end/step columns and a range function.
23
pub(super) fn numeric_ranges_impl_broadcast<T, U, F>(
24
start: &ChunkedArray<T>,
25
end: &ChunkedArray<T>,
26
step: &Int64Chunked,
27
range_impl: F,
28
builder: &mut ListPrimitiveChunkedBuilder<U>,
29
) -> PolarsResult<Column>
30
where
31
T: PolarsIntegerType,
32
U: PolarsIntegerType,
33
F: Fn(T::Native, T::Native, i64, &mut ListPrimitiveChunkedBuilder<U>) -> PolarsResult<()>,
34
ListPrimitiveChunkedBuilder<U>: ListBuilderTrait,
35
{
36
match (start.len(), end.len(), step.len()) {
37
(len_start, len_end, len_step) if len_start == len_end && len_start == len_step => {
38
build_numeric_ranges::<_, _, _, T, U, F>(
39
start.downcast_iter().flatten(),
40
end.downcast_iter().flatten(),
41
step.downcast_iter().flatten(),
42
range_impl,
43
builder,
44
)?;
45
},
46
(1, len_end, 1) => {
47
let start_scalar = start.get(0);
48
let step_scalar = step.get(0);
49
match (start_scalar, step_scalar) {
50
(Some(start), Some(step)) => build_numeric_ranges::<_, _, _, T, U, F>(
51
std::iter::repeat(Some(&start)),
52
end.downcast_iter().flatten(),
53
std::iter::repeat(Some(&step)),
54
range_impl,
55
builder,
56
)?,
57
_ => build_nulls(builder, len_end),
58
}
59
},
60
(len_start, 1, 1) => {
61
let end_scalar = end.get(0);
62
let step_scalar = step.get(0);
63
match (end_scalar, step_scalar) {
64
(Some(end), Some(step)) => build_numeric_ranges::<_, _, _, T, U, F>(
65
start.downcast_iter().flatten(),
66
std::iter::repeat(Some(&end)),
67
std::iter::repeat(Some(&step)),
68
range_impl,
69
builder,
70
)?,
71
_ => build_nulls(builder, len_start),
72
}
73
},
74
(1, 1, len_step) => {
75
let start_scalar = start.get(0);
76
let end_scalar = end.get(0);
77
match (start_scalar, end_scalar) {
78
(Some(start), Some(end)) => build_numeric_ranges::<_, _, _, T, U, F>(
79
std::iter::repeat(Some(&start)),
80
std::iter::repeat(Some(&end)),
81
step.downcast_iter().flatten(),
82
range_impl,
83
builder,
84
)?,
85
_ => build_nulls(builder, len_step),
86
}
87
},
88
(len_start, len_end, 1) if len_start == len_end => {
89
let step_scalar = step.get(0);
90
match step_scalar {
91
Some(step) => build_numeric_ranges::<_, _, _, T, U, F>(
92
start.downcast_iter().flatten(),
93
end.downcast_iter().flatten(),
94
std::iter::repeat(Some(&step)),
95
range_impl,
96
builder,
97
)?,
98
None => build_nulls(builder, len_start),
99
}
100
},
101
(len_start, 1, len_step) if len_start == len_step => {
102
let end_scalar = end.get(0);
103
match end_scalar {
104
Some(end) => build_numeric_ranges::<_, _, _, T, U, F>(
105
start.downcast_iter().flatten(),
106
std::iter::repeat(Some(&end)),
107
step.downcast_iter().flatten(),
108
range_impl,
109
builder,
110
)?,
111
None => build_nulls(builder, len_start),
112
}
113
},
114
(1, len_end, len_step) if len_end == len_step => {
115
let start_scalar = start.get(0);
116
match start_scalar {
117
Some(start) => build_numeric_ranges::<_, _, _, T, U, F>(
118
std::iter::repeat(Some(&start)),
119
end.downcast_iter().flatten(),
120
step.downcast_iter().flatten(),
121
range_impl,
122
builder,
123
)?,
124
None => build_nulls(builder, len_end),
125
}
126
},
127
(len_start, len_end, len_step) => {
128
polars_bail!(
129
ComputeError:
130
"lengths of `start` ({}), `end` ({}) and `step` ({}) do not match",
131
len_start, len_end, len_step
132
)
133
},
134
};
135
let out = builder.finish().into_column();
136
Ok(out)
137
}
138
139
/// Create a ranges column from the given start/end columns and a range function.
140
pub(super) fn temporal_ranges_impl_broadcast<T, U, F>(
141
start: &ChunkedArray<T>,
142
end: &ChunkedArray<T>,
143
range_impl: F,
144
builder: &mut ListPrimitiveChunkedBuilder<U>,
145
) -> PolarsResult<Column>
146
where
147
T: PolarsIntegerType,
148
U: PolarsIntegerType,
149
F: Fn(T::Native, T::Native, &mut ListPrimitiveChunkedBuilder<U>) -> PolarsResult<()>,
150
ListPrimitiveChunkedBuilder<U>: ListBuilderTrait,
151
{
152
match (start.len(), end.len()) {
153
(len_start, len_end) if len_start == len_end => {
154
build_temporal_ranges::<_, _, T, U, F>(
155
start.downcast_iter().flatten(),
156
end.downcast_iter().flatten(),
157
range_impl,
158
builder,
159
)?;
160
},
161
(1, len_end) => {
162
let start_scalar = start.get(0);
163
match start_scalar {
164
Some(start) => build_temporal_ranges::<_, _, T, U, F>(
165
std::iter::repeat(Some(&start)),
166
end.downcast_iter().flatten(),
167
range_impl,
168
builder,
169
)?,
170
None => build_nulls(builder, len_end),
171
}
172
},
173
(len_start, 1) => {
174
let end_scalar = end.get(0);
175
match end_scalar {
176
Some(end) => build_temporal_ranges::<_, _, T, U, F>(
177
start.downcast_iter().flatten(),
178
std::iter::repeat(Some(&end)),
179
range_impl,
180
builder,
181
)?,
182
None => build_nulls(builder, len_start),
183
}
184
},
185
(len_start, len_end) => {
186
polars_bail!(
187
ComputeError:
188
"lengths of `start` ({}) and `end` ({}) do not match",
189
len_start, len_end
190
)
191
},
192
};
193
let out = builder.finish().into_column();
194
Ok(out)
195
}
196
197
/// Iterate over a start and end column and create a range with the step for each entry.
198
fn build_numeric_ranges<'a, I, J, K, T, U, F>(
199
start: I,
200
end: J,
201
step: K,
202
range_impl: F,
203
builder: &mut ListPrimitiveChunkedBuilder<U>,
204
) -> PolarsResult<()>
205
where
206
I: Iterator<Item = Option<&'a T::Native>>,
207
J: Iterator<Item = Option<&'a T::Native>>,
208
K: Iterator<Item = Option<&'a i64>>,
209
T: PolarsIntegerType,
210
U: PolarsIntegerType,
211
F: Fn(T::Native, T::Native, i64, &mut ListPrimitiveChunkedBuilder<U>) -> PolarsResult<()>,
212
ListPrimitiveChunkedBuilder<U>: ListBuilderTrait,
213
{
214
for ((start, end), step) in start.zip(end).zip(step) {
215
match (start, end, step) {
216
(Some(start), Some(end), Some(step)) => range_impl(*start, *end, *step, builder)?,
217
_ => builder.append_null(),
218
}
219
}
220
Ok(())
221
}
222
223
/// Iterate over a start and end column and create a range for each entry.
224
fn build_temporal_ranges<'a, I, J, T, U, F>(
225
start: I,
226
end: J,
227
range_impl: F,
228
builder: &mut ListPrimitiveChunkedBuilder<U>,
229
) -> PolarsResult<()>
230
where
231
I: Iterator<Item = Option<&'a T::Native>>,
232
J: Iterator<Item = Option<&'a T::Native>>,
233
T: PolarsIntegerType,
234
U: PolarsIntegerType,
235
F: Fn(T::Native, T::Native, &mut ListPrimitiveChunkedBuilder<U>) -> PolarsResult<()>,
236
ListPrimitiveChunkedBuilder<U>: ListBuilderTrait,
237
{
238
for (start, end) in start.zip(end) {
239
match (start, end) {
240
(Some(start), Some(end)) => range_impl(*start, *end, builder)?,
241
_ => builder.append_null(),
242
}
243
}
244
Ok(())
245
}
246
247
/// Add `n` nulls to the builder.
248
pub fn build_nulls<U>(builder: &mut ListPrimitiveChunkedBuilder<U>, n: usize)
249
where
250
U: PolarsNumericType,
251
ListPrimitiveChunkedBuilder<U>: ListBuilderTrait,
252
{
253
for _ in 0..n {
254
builder.append_null()
255
}
256
}
257
258