Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
pola-rs
GitHub Repository: pola-rs/polars
Path: blob/main/crates/polars-ops/src/chunked_array/array/get.rs
8354 views
1
use polars_compute::gather::sublist::fixed_size_list::{
2
sub_fixed_size_list_get, sub_fixed_size_list_get_literal,
3
};
4
use polars_core::prelude::arity::{try_binary_to_series, try_unary_to_series};
5
6
use super::*;
7
use crate::series::convert_and_bound_idx_ca;
8
9
/// Get the value by literal index in the array.
10
/// So index `0` would return the first item of every sub-array
11
/// and index `-1` would return the last item of every sub-array
12
/// if an index is out of bounds, it will return a `None`.
13
pub fn array_get(
14
ca: &ArrayChunked,
15
index: &Int64Chunked,
16
null_on_oob: bool,
17
) -> PolarsResult<Series> {
18
polars_ensure!(ca.width() < IdxSize::MAX as usize, ComputeError: "`arr.get` not supported for such wide arrays");
19
20
// Base case. No overflow.
21
if ca.width() * ca.len() < IdxSize::MAX as usize {
22
return array_get_impl(ca, index, null_on_oob);
23
}
24
25
// If the array width * length would overflow. Do it part-by-part.
26
assert!(ca.len() != 1 || index.len() != 1);
27
let rows_per_slice = IdxSize::MAX as usize / ca.width();
28
29
let mut ca = ca.clone();
30
let mut index = index.clone();
31
let current_ca;
32
let current_index;
33
if ca.len() == 1 {
34
current_ca = ca.clone();
35
} else {
36
(current_ca, ca) = ca.split_at(rows_per_slice as i64);
37
}
38
if index.len() == 1 {
39
current_index = index.clone();
40
} else {
41
(current_index, index) = index.split_at(rows_per_slice as i64);
42
}
43
let mut s = array_get_impl(&current_ca, &current_index, null_on_oob)?;
44
45
while !ca.is_empty() && !index.is_empty() {
46
let current_ca;
47
let current_index;
48
if ca.len() == 1 {
49
current_ca = ca.clone();
50
} else {
51
(current_ca, ca) = ca.split_at(rows_per_slice as i64);
52
}
53
if index.len() == 1 {
54
current_index = index.clone();
55
} else {
56
(current_index, index) = index.split_at(rows_per_slice as i64);
57
}
58
s.append_owned(array_get_impl(&current_ca, &current_index, null_on_oob)?)?;
59
}
60
61
Ok(s)
62
}
63
64
fn array_get_impl(
65
ca: &ArrayChunked,
66
index: &Int64Chunked,
67
null_on_oob: bool,
68
) -> PolarsResult<Series> {
69
match index.len() {
70
1 => {
71
if let Some(index) = index.get(0) {
72
let out = try_unary_to_series(ca, |arr| {
73
sub_fixed_size_list_get_literal(arr, index, null_on_oob)
74
})?;
75
unsafe { out.from_physical_unchecked(ca.inner_dtype()) }
76
} else {
77
Ok(Series::full_null(
78
ca.name().clone(),
79
ca.len(),
80
ca.inner_dtype(),
81
))
82
}
83
},
84
85
len if len == ca.len() => {
86
let out = try_binary_to_series(ca, index, |arr, idx_arr| {
87
sub_fixed_size_list_get(arr, idx_arr, null_on_oob)
88
})?;
89
unsafe { out.from_physical_unchecked(ca.inner_dtype()) }
90
},
91
92
_len if ca.len() == 1 => {
93
if let Some(arr) = ca.get(0) {
94
let idx = convert_and_bound_idx_ca(index, arr.len(), null_on_oob)?;
95
let s = Series::try_from((ca.name().clone(), vec![arr])).unwrap();
96
unsafe {
97
s.take_unchecked(&idx)
98
.from_physical_unchecked(ca.inner_dtype())
99
}
100
} else {
101
Ok(Series::full_null(
102
ca.name().clone(),
103
ca.len(),
104
ca.inner_dtype(),
105
))
106
}
107
},
108
109
len => polars_bail!(
110
ComputeError:
111
"`arr.get` expression got an index array of length {} while the array has {} elements",
112
len, ca.len()
113
),
114
}
115
}
116
117