axion_data/series/
list.rs

1use crate::dtype::DataType;
2use crate::error::{AxionError, AxionResult};
3use super::core::Series;
4use super::interface::SeriesTrait;
5use std::any::Any;
6use std::cmp::Ordering;
7use std::fmt::{self, Debug, Display};
8
9/// 表示包含其他 Series 的列表类型 Series
10/// 
11/// ListSeries 允许在 DataFrame 的单个列中存储复杂的嵌套数据结构。
12/// 每个元素本身就是一个 Series,支持不同长度的子 Series。
13/// 
14/// # 特性
15/// 
16/// - 支持嵌套的数据结构
17/// - 内部 Series 可以有不同的长度
18/// - 统一的内部元素类型约束
19/// - 完整的 SeriesTrait 实现
20#[derive(Clone)]
21pub struct ListSeries {
22    name: String,
23    /// 数据是 Box<dyn SeriesTrait> 的 Option Vec
24    data: Vec<Option<Box<dyn SeriesTrait>>>,
25    /// 存储列表内部元素的统一数据类型
26    inner_dtype: DataType,
27}
28
29impl ListSeries {
30    /// 创建一个新的 ListSeries
31    /// 
32    /// # 参数
33    /// 
34    /// * `name` - Series 名称
35    /// * `data` - Series 数据向量
36    /// * `inner_dtype` - 内部元素的统一数据类型
37    pub fn new(name: String, data: Vec<Option<Box<dyn SeriesTrait>>>, inner_dtype: DataType) -> Self {
38        ListSeries { name, data, inner_dtype }
39    }
40
41    /// 获取指定索引处的内部 Series
42    /// 
43    /// # 参数
44    /// 
45    /// * `index` - 元素索引
46    /// 
47    /// # 返回值
48    /// 
49    /// 如果索引有效且值不为 null,返回内部 Series 的引用
50    pub fn get_inner_series(&self, index: usize) -> Option<&dyn SeriesTrait> {
51        self.data.get(index).and_then(|opt_box| opt_box.as_deref())
52    }
53}
54
55// 为 ListSeries 实现 SeriesTrait
56impl SeriesTrait for ListSeries {
57    fn name(&self) -> &str {
58        &self.name
59    }
60
61    fn dtype(&self) -> DataType {
62        // 返回 List 类型,包含内部类型信息
63        DataType::List(Box::new(self.inner_dtype.clone()))
64    }
65
66    fn len(&self) -> usize {
67        self.data.len()
68    }
69
70    fn is_empty(&self) -> bool {
71        self.data.is_empty()
72    }
73
74    fn as_any(&self) -> &dyn Any {
75        self
76    }
77
78    fn as_any_mut(&mut self) -> &mut dyn Any {
79        self
80    }
81
82    fn clone_box(&self) -> Box<dyn SeriesTrait> {
83        // 需要 ListSeries 实现 Clone 
84        Box::new(self.clone())
85    }
86
87    // get_str 的实现比较复杂,需要决定如何显示内部的 Series 
88    fn get_str(&self, index: usize) -> Option<String> {
89        self.data.get(index).and_then(|opt_box| {
90            opt_box.as_ref().map(|inner_series| {
91                // --- 修改这里 --- 
92                // 1. 检查内部 Series 是否为空
93                if inner_series.is_empty() {
94                    return "[]".to_string();
95                }
96
97                // 2. 获取内部 Series 的前几个元素的字符串表示
98                let max_elements_to_show = 5; // 最多显示多少个元素
99                let mut elements_str = Vec::with_capacity(max_elements_to_show);
100                for i in 0..std::cmp::min(inner_series.len(), max_elements_to_show) {
101                    // 调用内部 Series 的 get_str 获取每个元素的字符串
102                    elements_str.push(inner_series.get_str(i).unwrap_or_else(|| "null".to_string()));
103                }
104
105                // 3. 组合成列表字符串
106                let mut result = format!("[{}", elements_str.join(", "));
107
108                // 4. 如果内部 Series 元素过多,添加省略号
109                if inner_series.len() > max_elements_to_show {
110                    result.push_str(", ...");
111                }
112                result.push(']');
113                result
114            })
115        })
116    }
117
118    // slice 实现
119    fn slice(&self, start: usize, length: usize) -> Box<dyn SeriesTrait> {
120        let end = std::cmp::min(start + length, self.len());
121        let start = std::cmp::min(start, end);
122        let sliced_data = self.data[start..end].to_vec(); // Vec<Option<Box<dyn SeriesTrait>>> 支持 Clone
123        Box::new(ListSeries::new(self.name.clone(), sliced_data, self.inner_dtype.clone()))
124    }
125
126    // filter 实现 (需要 Series<bool>)
127    fn filter(&self, mask: &Series<bool>) -> AxionResult<Box<dyn SeriesTrait>> {
128        if mask.len() != self.len() {
129             return Err(AxionError::MismatchedLengths {
130                 expected: self.len(),
131                 found: mask.len(),
132                 name: format!("filter mask for list series '{}'", self.name),
133             });
134        }
135        let mut new_data = Vec::with_capacity(self.len());
136        for (opt_val, opt_mask) in self.data.iter().zip(mask.data_internal().iter()) {
137            if let Some(true) = opt_mask {
138                new_data.push(opt_val.clone());
139            }
140        }
141        Ok(Box::new(ListSeries::new(self.name.clone(), new_data, self.inner_dtype.clone())))
142    }
143
144    // take_indices 实现
145    fn take_indices(&self, indices: &[usize]) -> AxionResult<Box<dyn SeriesTrait>> {
146        let mut new_data = Vec::with_capacity(indices.len());
147        for &idx in indices {
148            let opt_val = self.data.get(idx)
149                .ok_or_else(|| AxionError::IndexOutOfBounds(idx, self.len()))?
150                .clone();
151            new_data.push(opt_val);
152        }
153        Ok(Box::new(ListSeries::new(self.name.clone(), new_data, self.inner_dtype.clone())))
154    }
155
156    fn take_indices_option(&self, indices: &[Option<usize>]) -> AxionResult<Box<dyn SeriesTrait>> {
157        let mut new_data = Vec::with_capacity(indices.len());
158        for opt_idx in indices {
159            match opt_idx {
160                Some(idx) => {
161                    // 获取 Option<Box<dyn SeriesTrait>> 并克隆
162                    let opt_val = self.data.get(*idx)
163                        .ok_or_else(|| AxionError::IndexOutOfBounds(*idx, self.len()))?
164                        .clone();
165                    new_data.push(opt_val);
166                }
167                None => {
168                    // 索引为 None 时,插入 None 值
169                    new_data.push(None);
170                }
171            }
172        }
173        Ok(Box::new(ListSeries::new(self.name.clone(), new_data, self.inner_dtype.clone())))
174    }
175
176    fn rename(&mut self, new_name: &str) {
177        self.name = new_name.to_string();
178    }
179
180    /// Compares this ListSeries with another SeriesTrait object for equality.
181    fn series_equal(&self, other: &dyn SeriesTrait) -> bool {
182        // 1. 检查对方是否也是 ListSeries
183        if let Some(other_list) = other.as_any().downcast_ref::<ListSeries>() {
184            // 2. 检查内部类型是否一致
185            if self.inner_dtype != other_list.inner_dtype {
186                return false;
187            }
188            // 3. 检查长度是否一致
189            if self.len() != other_list.len() {
190                return false;
191            }
192            // 4. 逐一比较内部的 Option<Box<dyn SeriesTrait>>
193            self.data.iter().zip(other_list.data.iter()).all(|(self_opt_box, other_opt_box)| {
194                match (self_opt_box, other_opt_box) {
195                    // 两个都是 None,相等
196                    (None, None) => true,
197                    // 两个都是 Some,递归比较内部的 Series
198                    (Some(self_inner_series), Some(other_inner_series)) => {
199                        // 调用内部 Series 的 series_equal 方法
200                        self_inner_series.series_equal(&**other_inner_series)
201                    }
202                    // 一个 Some 一个 None,不相等
203                    _ => false,
204                }
205            })
206        } else {
207            // 类型不匹配,肯定不相等
208            false
209        }
210    }
211
212    fn compare_row(&self, _a_idx: usize, _b_idx: usize) -> Ordering {
213        // List 类型通常不支持直接比较行来进行排序
214        // 返回 Equal 表示此列不影响排序顺序
215        Ordering::Equal
216        // 或者,如果你想禁止按 List 列排序,可以在 DataFrame::sort 中检查并返回错误
217    }
218
219    fn get_as_f64(&self, index: usize) -> AxionResult<Option<f64>> {
220        let _index = index; // 这里的 index 是 ListSeries 的索引
221        Ok(None)
222    }    
223
224    fn is_null_at(&self, index: usize) -> bool {
225        // self.data is Vec<Option<T>>
226        // If index is out of bounds, get returns None, map_or returns true (treat as null)
227        // If index is valid, opt_val_ref is &Option<T>, is_none() checks if this Option<T> is None
228        self.data.get(index).map_or(true, |opt_val_ref| opt_val_ref.is_none())
229    }
230}
231
232// --- (可选) 实现 Debug 和 Display for ListSeries --- 
233impl Debug for ListSeries {
234     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
235         f.debug_struct("ListSeries")
236          .field("name", &self.name)
237          .field("dtype", &self.dtype()) // 调用 dtype() 方法
238          .field("len", &self.len())
239          .field("data_head", &self.data.iter().take(5).collect::<Vec<_>>()) // 只显示前几个内部 Series 的 Debug
240          .finish()
241     }
242}
243
244impl Display for ListSeries {
245    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
246        writeln!(f, "ListSeries: '{}' [{:?}]", self.name, self.dtype())?;
247        for (i, opt_val) in self.data.iter().take(10).enumerate() {
248            write!(f, "{}: ", i)?;
249            match opt_val {
250                Some(val) => writeln!(f, "{:?}", val)?, // 使用 Debug 打印内部 Series
251                None => writeln!(f, "null")?,
252            }
253        }
254        if self.len() > 10 {
255            writeln!(f, "... ({} more)", self.len() - 10)?;
256        }
257        Ok(())
258    }
259}
260
261/// 创建一个新的 ListSeries,并验证类型一致性
262/// 
263/// 该函数会检查所有输入 Series 是否具有相同的数据类型,
264/// 如果类型不一致会返回错误。
265/// 
266/// # 参数
267/// 
268/// * `name` - Series 名称
269/// * `data` - Series 数据向量
270/// 
271/// # 返回值
272/// 
273/// 成功时返回新创建的 ListSeries,失败时返回错误
274/// 
275/// # 错误
276/// 
277/// 当内部 Series 类型不一致时返回错误
278pub fn new_list_series(name: String, data: Vec<Box<dyn SeriesTrait>>) -> AxionResult<ListSeries> {
279    let inner_dtype = data.first()
280        .map(|s| s.dtype())
281        .unwrap_or(DataType::Null);
282
283    for series in data.iter().skip(1) {
284        if series.dtype() != inner_dtype {
285            return Err(AxionError::Other(format!(
286                "List series '{}' expects inner type {:?} but found {:?}",
287                name, inner_dtype, series.dtype()
288            )));
289        }
290    }
291
292    let data_opts = data.into_iter().map(Some).collect();
293
294    Ok(ListSeries::new(name, data_opts, inner_dtype))
295}