Path: blob/main/crates/polars-ops/src/chunked_array/array/get.rs
6939 views
use arrow::array::Array;1use polars_compute::gather::sublist::fixed_size_list::{2sub_fixed_size_list_get, sub_fixed_size_list_get_literal,3};4use polars_core::utils::align_chunks_binary;56use super::*;78fn array_get_literal(ca: &ArrayChunked, idx: i64, null_on_oob: bool) -> PolarsResult<Series> {9let chunks = ca10.downcast_iter()11.map(|arr| sub_fixed_size_list_get_literal(arr, idx, null_on_oob))12.collect::<PolarsResult<Vec<_>>>()?;13Series::try_from((ca.name().clone(), chunks))14.unwrap()15.cast(ca.inner_dtype())16}1718/// Get the value by literal index in the array.19/// So index `0` would return the first item of every sub-array20/// and index `-1` would return the last item of every sub-array21/// if an index is out of bounds, it will return a `None`.22pub fn array_get(23ca: &ArrayChunked,24index: &Int64Chunked,25null_on_oob: bool,26) -> PolarsResult<Series> {27polars_ensure!(ca.width() < IdxSize::MAX as usize, ComputeError: "`arr.get` not supported for such wide arrays");2829// Base case. No overflow.30if ca.width() * ca.len() < IdxSize::MAX as usize {31return array_get_impl(ca, index, null_on_oob);32}3334// If the array width * length would overflow. Do it part-by-part.35assert!(ca.len() != 1 || index.len() != 1);36let rows_per_slice = IdxSize::MAX as usize / ca.width();3738let mut ca = ca.clone();39let mut index = index.clone();40let current_ca;41let current_index;42if ca.len() == 1 {43current_ca = ca.clone();44} else {45(current_ca, ca) = ca.split_at(rows_per_slice as i64);46}47if index.len() == 1 {48current_index = index.clone();49} else {50(current_index, index) = index.split_at(rows_per_slice as i64);51}52let mut s = array_get_impl(¤t_ca, ¤t_index, null_on_oob)?;5354while !ca.is_empty() && !index.is_empty() {55let current_ca;56let current_index;57if ca.len() == 1 {58current_ca = ca.clone();59} else {60(current_ca, ca) = ca.split_at(rows_per_slice as i64);61}62if index.len() == 1 {63current_index = index.clone();64} else {65(current_index, index) = index.split_at(rows_per_slice as i64);66}67s.append_owned(array_get_impl(¤t_ca, ¤t_index, null_on_oob)?)?;68}6970Ok(s)71}7273fn array_get_impl(74ca: &ArrayChunked,75index: &Int64Chunked,76null_on_oob: bool,77) -> PolarsResult<Series> {78match index.len() {791 => {80let index = index.get(0);81if let Some(index) = index {82array_get_literal(ca, index, null_on_oob)83} else {84Ok(Series::full_null(85ca.name().clone(),86ca.len(),87ca.inner_dtype(),88))89}90},91len if len == ca.len() => {92let out = binary_to_series_arr_get(ca, index, null_on_oob, |arr, idx, nob| {93sub_fixed_size_list_get(arr, idx, nob)94});95out?.cast(ca.inner_dtype())96},97len => polars_bail!(98ComputeError:99"`arr.get` expression got an index array of length {} while the array has {} elements",100len, ca.len()101),102}103}104105pub fn binary_to_series_arr_get<T, U, F>(106lhs: &ChunkedArray<T>,107rhs: &ChunkedArray<U>,108null_on_oob: bool,109mut op: F,110) -> PolarsResult<Series>111where112T: PolarsDataType,113U: PolarsDataType,114F: FnMut(&T::Array, &U::Array, bool) -> PolarsResult<Box<dyn Array>>,115{116let (lhs, rhs) = align_chunks_binary(lhs, rhs);117let chunks = lhs118.downcast_iter()119.zip(rhs.downcast_iter())120.map(|(lhs_arr, rhs_arr)| op(lhs_arr, rhs_arr, null_on_oob))121.collect::<PolarsResult<Vec<_>>>()?;122Series::try_from((lhs.name().clone(), chunks))123}124125126