use crate::core::Series;
use crate::error::{Error, Result};
use ndarray::{Array1, Array2, ArrayView1, ArrayView2};
pub trait NdarraySeries {
fn to_series(&self) -> Result<Series>;
fn to_series_with_x(&self, x: &Self) -> Result<Series>;
}
impl NdarraySeries for Array1<f64> {
fn to_series(&self) -> Result<Series> {
let y = self.to_vec();
let x: Vec<f64> = (0..y.len()).map(|i| i as f64).collect();
Series::new(x, y)
}
fn to_series_with_x(&self, x: &Self) -> Result<Series> {
if self.len() != x.len() {
return Err(Error::InvalidData(
"X and Y arrays must have the same length".into(),
));
}
Series::new(x.to_vec(), self.to_vec())
}
}
impl NdarraySeries for ArrayView1<'_, f64> {
fn to_series(&self) -> Result<Series> {
let y = self.to_vec();
let x: Vec<f64> = (0..y.len()).map(|i| i as f64).collect();
Series::new(x, y)
}
fn to_series_with_x(&self, x: &Self) -> Result<Series> {
if self.len() != x.len() {
return Err(Error::InvalidData(
"X and Y arrays must have the same length".into(),
));
}
Series::new(x.to_vec(), self.to_vec())
}
}
pub trait NdarrayMultiSeries {
fn to_multi_series(&self) -> Result<Vec<Series>>;
fn rows_to_series(&self) -> Result<Vec<Series>>;
}
impl NdarrayMultiSeries for Array2<f64> {
fn to_multi_series(&self) -> Result<Vec<Series>> {
if self.ncols() < 2 {
return Err(Error::InvalidData(
"Array must have at least 2 columns (x and at least one y)".into(),
));
}
let x_col = self.column(0).to_vec();
let mut series_vec = Vec::new();
for col_idx in 1..self.ncols() {
let y_col = self.column(col_idx).to_vec();
series_vec.push(Series::new(x_col.clone(), y_col)?);
}
Ok(series_vec)
}
fn rows_to_series(&self) -> Result<Vec<Series>> {
let mut series_vec = Vec::new();
for row in self.rows() {
let y = row.to_vec();
let x: Vec<f64> = (0..y.len()).map(|i| i as f64).collect();
series_vec.push(Series::new(x, y)?);
}
Ok(series_vec)
}
}
impl NdarrayMultiSeries for ArrayView2<'_, f64> {
fn to_multi_series(&self) -> Result<Vec<Series>> {
if self.ncols() < 2 {
return Err(Error::InvalidData(
"Array must have at least 2 columns (x and at least one y)".into(),
));
}
let x_col = self.column(0).to_vec();
let mut series_vec = Vec::new();
for col_idx in 1..self.ncols() {
let y_col = self.column(col_idx).to_vec();
series_vec.push(Series::new(x_col.clone(), y_col)?);
}
Ok(series_vec)
}
fn rows_to_series(&self) -> Result<Vec<Series>> {
let mut series_vec = Vec::new();
for row in self.rows() {
let y = row.to_vec();
let x: Vec<f64> = (0..y.len()).map(|i| i as f64).collect();
series_vec.push(Series::new(x, y)?);
}
Ok(series_vec)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::core::DataSeries;
use ndarray::array;
#[test]
fn test_array1_to_series() {
let y = array![1.0, 4.0, 9.0, 16.0];
let series = y.to_series().unwrap();
assert_eq!(series.len(), 4);
}
#[test]
fn test_array1_to_series_with_x() {
let x = array![0.0, 1.0, 2.0, 3.0];
let y = array![1.0, 4.0, 9.0, 16.0];
let series = y.to_series_with_x(&x).unwrap();
assert_eq!(series.len(), 4);
}
#[test]
fn test_array2_to_multi_series() {
let data = array![[0.0, 1.0, 2.0], [1.0, 4.0, 3.0], [2.0, 9.0, 4.0],];
let series_list = data.to_multi_series().unwrap();
assert_eq!(series_list.len(), 2);
}
#[test]
fn test_array2_rows_to_series() {
let data = array![[1.0, 4.0, 9.0], [2.0, 5.0, 8.0],];
let series_list = data.rows_to_series().unwrap();
assert_eq!(series_list.len(), 2);
}
}