Path: blob/main/crates/polars-core/src/series/iterator.rs
8421 views
use crate::prelude::any_value::arr_to_any_value;1use crate::prelude::*;2use crate::utils::NoNull;34macro_rules! from_iterator {5($native:ty, $variant:ident) => {6impl FromIterator<Option<$native>> for Series {7fn from_iter<I: IntoIterator<Item = Option<$native>>>(iter: I) -> Self {8let ca: ChunkedArray<$variant> = iter.into_iter().collect();9ca.into_series()10}11}1213impl FromIterator<$native> for Series {14fn from_iter<I: IntoIterator<Item = $native>>(iter: I) -> Self {15let ca: NoNull<ChunkedArray<$variant>> = iter.into_iter().collect();16ca.into_inner().into_series()17}18}1920impl<'a> FromIterator<&'a $native> for Series {21fn from_iter<I: IntoIterator<Item = &'a $native>>(iter: I) -> Self {22let ca: ChunkedArray<$variant> = iter.into_iter().map(|v| Some(*v)).collect();23ca.into_series()24}25}26};27}2829#[cfg(feature = "dtype-u8")]30from_iterator!(u8, UInt8Type);31#[cfg(feature = "dtype-u16")]32from_iterator!(u16, UInt16Type);33from_iterator!(u32, UInt32Type);34from_iterator!(u64, UInt64Type);35#[cfg(feature = "dtype-i8")]36from_iterator!(i8, Int8Type);37#[cfg(feature = "dtype-i16")]38from_iterator!(i16, Int16Type);39from_iterator!(i32, Int32Type);40from_iterator!(i64, Int64Type);41from_iterator!(f32, Float32Type);42from_iterator!(f64, Float64Type);43from_iterator!(bool, BooleanType);4445impl<'a> FromIterator<Option<&'a str>> for Series {46fn from_iter<I: IntoIterator<Item = Option<&'a str>>>(iter: I) -> Self {47let ca: StringChunked = iter.into_iter().collect();48ca.into_series()49}50}5152impl<'a> FromIterator<&'a str> for Series {53fn from_iter<I: IntoIterator<Item = &'a str>>(iter: I) -> Self {54let ca: StringChunked = iter.into_iter().collect();55ca.into_series()56}57}5859impl FromIterator<Option<String>> for Series {60fn from_iter<T: IntoIterator<Item = Option<String>>>(iter: T) -> Self {61let ca: StringChunked = iter.into_iter().collect();62ca.into_series()63}64}6566impl FromIterator<String> for Series {67fn from_iter<I: IntoIterator<Item = String>>(iter: I) -> Self {68let ca: StringChunked = iter.into_iter().collect();69ca.into_series()70}71}7273pub type SeriesPhysIter<'a> = Box<dyn ExactSizeIterator<Item = AnyValue<'a>> + 'a>;7475impl Series {76/// Iterate over [`Series`] as [`AnyValue`].77///78/// # Panics79/// This will panic if the array is not rechunked first.80pub fn iter(&self) -> SeriesIter<'_> {81let arrays = self.chunks();82SeriesIter {83idx_in_cur_arr: 0,84cur_arr_idx: 0,85cur_arr_len: arrays[0].len(),86arrays,87dtype: self.dtype(),88total_elems_in_remaining_arrays: self.len(),89}90}9192pub fn phys_iter(&self) -> SeriesPhysIter<'_> {93let dtype = self.dtype();94let phys_dtype = dtype.to_physical();9596assert_eq!(dtype, &phys_dtype, "impl error");97assert_eq!(self.chunks().len(), 1, "impl error");98let arr = &*self.chunks()[0];99100if phys_dtype.is_primitive_numeric() {101if arr.null_count() == 0 {102with_match_physical_numeric_type!(phys_dtype, |$T| {103let arr = arr.as_any().downcast_ref::<PrimitiveArray<$T>>().unwrap();104let values = arr.values().as_slice();105Box::new(values.iter().map(|&value| AnyValue::from(value))) as Box<dyn ExactSizeIterator<Item=AnyValue<'_>> + '_>106})107} else {108with_match_physical_numeric_type!(phys_dtype, |$T| {109let arr = arr.as_any().downcast_ref::<PrimitiveArray<$T>>().unwrap();110Box::new(arr.iter().map(|value| {111112match value {113Some(value) => AnyValue::from(*value),114None => AnyValue::Null115}116117})) as Box<dyn ExactSizeIterator<Item=AnyValue<'_>> + '_>118})119}120} else {121match dtype {122DataType::String => {123let arr = arr.as_any().downcast_ref::<Utf8ViewArray>().unwrap();124if arr.null_count() == 0 {125Box::new(arr.values_iter().map(AnyValue::String))126as Box<dyn ExactSizeIterator<Item = AnyValue<'_>> + '_>127} else {128let zipvalid = arr.iter();129Box::new(zipvalid.unwrap_optional().map(|v| match v {130Some(value) => AnyValue::String(value),131None => AnyValue::Null,132}))133as Box<dyn ExactSizeIterator<Item = AnyValue<'_>> + '_>134}135},136DataType::Boolean => {137let arr = arr.as_any().downcast_ref::<BooleanArray>().unwrap();138if arr.null_count() == 0 {139Box::new(arr.values_iter().map(AnyValue::Boolean))140as Box<dyn ExactSizeIterator<Item = AnyValue<'_>> + '_>141} else {142let zipvalid = arr.iter();143Box::new(zipvalid.unwrap_optional().map(|v| match v {144Some(value) => AnyValue::Boolean(value),145None => AnyValue::Null,146}))147as Box<dyn ExactSizeIterator<Item = AnyValue<'_>> + '_>148}149},150_ => Box::new(self.iter()),151}152}153}154}155156pub struct SeriesIter<'a> {157arrays: &'a [Box<dyn Array>],158dtype: &'a DataType,159idx_in_cur_arr: usize,160cur_arr_len: usize,161cur_arr_idx: usize,162total_elems_in_remaining_arrays: usize,163}164165impl<'a> Iterator for SeriesIter<'a> {166type Item = AnyValue<'a>;167168#[inline]169fn next(&mut self) -> Option<Self::Item> {170loop {171if self.idx_in_cur_arr < self.cur_arr_len {172let arr = unsafe { self.arrays.get_unchecked(self.cur_arr_idx) };173let ret = unsafe { arr_to_any_value(&**arr, self.idx_in_cur_arr, self.dtype) };174self.idx_in_cur_arr += 1;175return Some(ret);176}177178if self.cur_arr_idx + 1 < self.arrays.len() {179self.total_elems_in_remaining_arrays -= self.cur_arr_len;180self.cur_arr_idx += 1;181self.idx_in_cur_arr = 0;182let arr = unsafe { self.arrays.get_unchecked(self.cur_arr_idx) };183self.cur_arr_len = arr.len();184} else {185return None;186}187}188}189190fn size_hint(&self) -> (usize, Option<usize>) {191let len = self.total_elems_in_remaining_arrays - self.idx_in_cur_arr;192(len, Some(len))193}194}195196impl ExactSizeIterator for SeriesIter<'_> {}197198#[cfg(test)]199mod test {200use crate::prelude::*;201202#[test]203fn test_iter() {204let a = Series::new("age".into(), [23, 71, 9].as_ref());205let _b = a206.i32()207.unwrap()208.into_iter()209.map(|opt_v| opt_v.map(|v| v * 2));210}211212#[test]213fn test_iter_str() {214let data = [Some("John"), Some("Doe"), None];215let a: Series = data.into_iter().collect();216let b = Series::new("".into(), data);217assert_eq!(a, b);218}219220#[test]221fn test_iter_string() {222let data = [Some("John".to_string()), Some("Doe".to_string()), None];223let a: Series = data.clone().into_iter().collect();224let b = Series::new("".into(), data);225assert_eq!(a, b);226}227}228229230