Path: blob/main/crates/polars-core/src/series/iterator.rs
6940 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 dtype = self.dtype();82#[cfg(feature = "object")]83assert!(84!matches!(dtype, DataType::Object(_)),85"object dtype not supported in Series.iter"86);87assert_eq!(self.chunks().len(), 1, "impl error");88let arr = &*self.chunks()[0];89let len = arr.len();90SeriesIter {91arr,92dtype,93idx: 0,94len,95}96}9798pub fn phys_iter(&self) -> SeriesPhysIter<'_> {99let dtype = self.dtype();100let phys_dtype = dtype.to_physical();101102assert_eq!(dtype, &phys_dtype, "impl error");103assert_eq!(self.chunks().len(), 1, "impl error");104#[cfg(feature = "object")]105assert!(106!matches!(dtype, DataType::Object(_)),107"object dtype not supported in Series.iter"108);109let arr = &*self.chunks()[0];110111if phys_dtype.is_primitive_numeric() {112if arr.null_count() == 0 {113with_match_physical_numeric_type!(phys_dtype, |$T| {114let arr = arr.as_any().downcast_ref::<PrimitiveArray<$T>>().unwrap();115let values = arr.values().as_slice();116Box::new(values.iter().map(|&value| AnyValue::from(value))) as Box<dyn ExactSizeIterator<Item=AnyValue<'_>> + '_>117})118} else {119with_match_physical_numeric_type!(phys_dtype, |$T| {120let arr = arr.as_any().downcast_ref::<PrimitiveArray<$T>>().unwrap();121Box::new(arr.iter().map(|value| {122123match value {124Some(value) => AnyValue::from(*value),125None => AnyValue::Null126}127128})) as Box<dyn ExactSizeIterator<Item=AnyValue<'_>> + '_>129})130}131} else {132match dtype {133DataType::String => {134let arr = arr.as_any().downcast_ref::<Utf8ViewArray>().unwrap();135if arr.null_count() == 0 {136Box::new(arr.values_iter().map(AnyValue::String))137as Box<dyn ExactSizeIterator<Item = AnyValue<'_>> + '_>138} else {139let zipvalid = arr.iter();140Box::new(zipvalid.unwrap_optional().map(|v| match v {141Some(value) => AnyValue::String(value),142None => AnyValue::Null,143}))144as Box<dyn ExactSizeIterator<Item = AnyValue<'_>> + '_>145}146},147DataType::Boolean => {148let arr = arr.as_any().downcast_ref::<BooleanArray>().unwrap();149if arr.null_count() == 0 {150Box::new(arr.values_iter().map(AnyValue::Boolean))151as Box<dyn ExactSizeIterator<Item = AnyValue<'_>> + '_>152} else {153let zipvalid = arr.iter();154Box::new(zipvalid.unwrap_optional().map(|v| match v {155Some(value) => AnyValue::Boolean(value),156None => AnyValue::Null,157}))158as Box<dyn ExactSizeIterator<Item = AnyValue<'_>> + '_>159}160},161_ => Box::new(self.iter()),162}163}164}165}166167pub struct SeriesIter<'a> {168arr: &'a dyn Array,169dtype: &'a DataType,170idx: usize,171len: usize,172}173174impl<'a> Iterator for SeriesIter<'a> {175type Item = AnyValue<'a>;176177#[inline]178fn next(&mut self) -> Option<Self::Item> {179let idx = self.idx;180181if idx == self.len {182None183} else {184self.idx += 1;185unsafe { Some(arr_to_any_value(self.arr, idx, self.dtype)) }186}187}188189fn size_hint(&self) -> (usize, Option<usize>) {190(self.len, Some(self.len))191}192}193194impl ExactSizeIterator for SeriesIter<'_> {}195196#[cfg(test)]197mod test {198use crate::prelude::*;199200#[test]201fn test_iter() {202let a = Series::new("age".into(), [23, 71, 9].as_ref());203let _b = a204.i32()205.unwrap()206.into_iter()207.map(|opt_v| opt_v.map(|v| v * 2));208}209210#[test]211fn test_iter_str() {212let data = [Some("John"), Some("Doe"), None];213let a: Series = data.into_iter().collect();214let b = Series::new("".into(), data);215assert_eq!(a, b);216}217218#[test]219fn test_iter_string() {220let data = [Some("John".to_string()), Some("Doe".to_string()), None];221let a: Series = data.clone().into_iter().collect();222let b = Series::new("".into(), data);223assert_eq!(a, b);224}225}226227228