polars_core/series/
iterator.rs1use crate::prelude::any_value::arr_to_any_value;
2use crate::prelude::*;
3use crate::utils::NoNull;
4
5macro_rules! from_iterator {
6 ($native:ty, $variant:ident) => {
7 impl FromIterator<Option<$native>> for Series {
8 fn from_iter<I: IntoIterator<Item = Option<$native>>>(iter: I) -> Self {
9 let ca: ChunkedArray<$variant> = iter.into_iter().collect();
10 ca.into_series()
11 }
12 }
13
14 impl FromIterator<$native> for Series {
15 fn from_iter<I: IntoIterator<Item = $native>>(iter: I) -> Self {
16 let ca: NoNull<ChunkedArray<$variant>> = iter.into_iter().collect();
17 ca.into_inner().into_series()
18 }
19 }
20
21 impl<'a> FromIterator<&'a $native> for Series {
22 fn from_iter<I: IntoIterator<Item = &'a $native>>(iter: I) -> Self {
23 let ca: ChunkedArray<$variant> = iter.into_iter().map(|v| Some(*v)).collect();
24 ca.into_series()
25 }
26 }
27 };
28}
29
30#[cfg(feature = "dtype-u8")]
31from_iterator!(u8, UInt8Type);
32#[cfg(feature = "dtype-u16")]
33from_iterator!(u16, UInt16Type);
34from_iterator!(u32, UInt32Type);
35from_iterator!(u64, UInt64Type);
36#[cfg(feature = "dtype-i8")]
37from_iterator!(i8, Int8Type);
38#[cfg(feature = "dtype-i16")]
39from_iterator!(i16, Int16Type);
40from_iterator!(i32, Int32Type);
41from_iterator!(i64, Int64Type);
42from_iterator!(f32, Float32Type);
43from_iterator!(f64, Float64Type);
44from_iterator!(bool, BooleanType);
45
46impl<'a> FromIterator<Option<&'a str>> for Series {
47 fn from_iter<I: IntoIterator<Item = Option<&'a str>>>(iter: I) -> Self {
48 let ca: StringChunked = iter.into_iter().collect();
49 ca.into_series()
50 }
51}
52
53impl<'a> FromIterator<&'a str> for Series {
54 fn from_iter<I: IntoIterator<Item = &'a str>>(iter: I) -> Self {
55 let ca: StringChunked = iter.into_iter().collect();
56 ca.into_series()
57 }
58}
59
60impl FromIterator<Option<String>> for Series {
61 fn from_iter<T: IntoIterator<Item = Option<String>>>(iter: T) -> Self {
62 let ca: StringChunked = iter.into_iter().collect();
63 ca.into_series()
64 }
65}
66
67impl FromIterator<String> for Series {
68 fn from_iter<I: IntoIterator<Item = String>>(iter: I) -> Self {
69 let ca: StringChunked = iter.into_iter().collect();
70 ca.into_series()
71 }
72}
73
74pub type SeriesPhysIter<'a> = Box<dyn ExactSizeIterator<Item = AnyValue<'a>> + 'a>;
75
76impl Series {
77 pub fn iter(&self) -> SeriesIter<'_> {
82 let dtype = self.dtype();
83 #[cfg(feature = "object")]
84 assert!(
85 !matches!(dtype, DataType::Object(_)),
86 "object dtype not supported in Series.iter"
87 );
88 assert_eq!(self.chunks().len(), 1, "impl error");
89 let arr = &*self.chunks()[0];
90 let len = arr.len();
91 SeriesIter {
92 arr,
93 dtype,
94 idx: 0,
95 len,
96 }
97 }
98
99 pub fn phys_iter(&self) -> SeriesPhysIter<'_> {
100 let dtype = self.dtype();
101 let phys_dtype = dtype.to_physical();
102
103 assert_eq!(dtype, &phys_dtype, "impl error");
104 assert_eq!(self.chunks().len(), 1, "impl error");
105 #[cfg(feature = "object")]
106 assert!(
107 !matches!(dtype, DataType::Object(_)),
108 "object dtype not supported in Series.iter"
109 );
110 let arr = &*self.chunks()[0];
111
112 if phys_dtype.is_primitive_numeric() {
113 if arr.null_count() == 0 {
114 with_match_physical_numeric_type!(phys_dtype, |$T| {
115 let arr = arr.as_any().downcast_ref::<PrimitiveArray<$T>>().unwrap();
116 let values = arr.values().as_slice();
117 Box::new(values.iter().map(|&value| AnyValue::from(value))) as Box<dyn ExactSizeIterator<Item=AnyValue<'_>> + '_>
118 })
119 } else {
120 with_match_physical_numeric_type!(phys_dtype, |$T| {
121 let arr = arr.as_any().downcast_ref::<PrimitiveArray<$T>>().unwrap();
122 Box::new(arr.iter().map(|value| {
123
124 match value {
125 Some(value) => AnyValue::from(*value),
126 None => AnyValue::Null
127 }
128
129 })) as Box<dyn ExactSizeIterator<Item=AnyValue<'_>> + '_>
130 })
131 }
132 } else {
133 match dtype {
134 DataType::String => {
135 let arr = arr.as_any().downcast_ref::<Utf8ViewArray>().unwrap();
136 if arr.null_count() == 0 {
137 Box::new(arr.values_iter().map(AnyValue::String))
138 as Box<dyn ExactSizeIterator<Item = AnyValue<'_>> + '_>
139 } else {
140 let zipvalid = arr.iter();
141 Box::new(zipvalid.unwrap_optional().map(|v| match v {
142 Some(value) => AnyValue::String(value),
143 None => AnyValue::Null,
144 }))
145 as Box<dyn ExactSizeIterator<Item = AnyValue<'_>> + '_>
146 }
147 },
148 DataType::Boolean => {
149 let arr = arr.as_any().downcast_ref::<BooleanArray>().unwrap();
150 if arr.null_count() == 0 {
151 Box::new(arr.values_iter().map(AnyValue::Boolean))
152 as Box<dyn ExactSizeIterator<Item = AnyValue<'_>> + '_>
153 } else {
154 let zipvalid = arr.iter();
155 Box::new(zipvalid.unwrap_optional().map(|v| match v {
156 Some(value) => AnyValue::Boolean(value),
157 None => AnyValue::Null,
158 }))
159 as Box<dyn ExactSizeIterator<Item = AnyValue<'_>> + '_>
160 }
161 },
162 _ => Box::new(self.iter()),
163 }
164 }
165 }
166}
167
168pub struct SeriesIter<'a> {
169 arr: &'a dyn Array,
170 dtype: &'a DataType,
171 idx: usize,
172 len: usize,
173}
174
175impl<'a> Iterator for SeriesIter<'a> {
176 type Item = AnyValue<'a>;
177
178 #[inline]
179 fn next(&mut self) -> Option<Self::Item> {
180 let idx = self.idx;
181
182 if idx == self.len {
183 None
184 } else {
185 self.idx += 1;
186 unsafe { Some(arr_to_any_value(self.arr, idx, self.dtype)) }
187 }
188 }
189
190 fn size_hint(&self) -> (usize, Option<usize>) {
191 (self.len, Some(self.len))
192 }
193}
194
195impl ExactSizeIterator for SeriesIter<'_> {}
196
197#[cfg(test)]
198mod test {
199 use crate::prelude::*;
200
201 #[test]
202 fn test_iter() {
203 let a = Series::new("age".into(), [23, 71, 9].as_ref());
204 let _b = a
205 .i32()
206 .unwrap()
207 .into_iter()
208 .map(|opt_v| opt_v.map(|v| v * 2));
209 }
210
211 #[test]
212 fn test_iter_str() {
213 let data = [Some("John"), Some("Doe"), None];
214 let a: Series = data.into_iter().collect();
215 let b = Series::new("".into(), data);
216 assert_eq!(a, b);
217 }
218
219 #[test]
220 fn test_iter_string() {
221 let data = [Some("John".to_string()), Some("Doe".to_string()), None];
222 let a: Series = data.clone().into_iter().collect();
223 let b = Series::new("".into(), data);
224 assert_eq!(a, b);
225 }
226}