use std::fmt;
use std::error::Error;
use list_comprehension_macro::comp;
use crate::range::Range;
#[derive(Debug, Clone)]
pub enum MetaData {
StringMatrix (Vec<Vec<String>>),
StringArray (Vec<String> ),
FloatMatrix (Vec<Vec<f64>> ),
FloatArray (Vec<f64> ),
IntMatrix (Vec<Vec<i64>> ),
IntArray (Vec<i64> ),
RangeArray (Vec<Range> ),
}
impl MetaData {
pub fn len(&self) -> usize {
match self {
MetaData::FloatArray (v) => v.len(),
MetaData::IntArray (v) => v.len(),
MetaData::StringArray (v) => v.len(),
MetaData::StringMatrix(v) => v.len(),
MetaData::FloatMatrix (v) => v.len(),
MetaData::IntMatrix (v) => v.len(),
MetaData::RangeArray (v) => v.len(),
}
}
pub fn concat(&self, data : &Self) -> Result<Self, Box<dyn Error>> {
match (self, data) {
(MetaData::FloatArray (v), MetaData::FloatArray (w)) => Ok(MetaData::FloatArray ([v.clone(), w.clone()].concat())),
(MetaData::IntArray (v), MetaData::IntArray (w)) => Ok(MetaData::IntArray ([v.clone(), w.clone()].concat())),
(MetaData::StringArray (v), MetaData::StringArray (w)) => Ok(MetaData::StringArray ([v.clone(), w.clone()].concat())),
(MetaData::StringMatrix(v), MetaData::StringMatrix(w)) => Ok(MetaData::StringMatrix([v.clone(), w.clone()].concat())),
(MetaData::FloatMatrix (v), MetaData::FloatMatrix (w)) => Ok(MetaData::FloatMatrix ([v.clone(), w.clone()].concat())),
(MetaData::IntMatrix (v), MetaData::IntMatrix (w)) => Ok(MetaData::IntMatrix ([v.clone(), w.clone()].concat())),
(MetaData::RangeArray (v), MetaData::RangeArray (w)) => Ok(MetaData::RangeArray ([v.clone(), w.clone()].concat())),
_ => Err(format!("MetaData types do not match").into())
}
}
pub fn slice(&self, ifrom : usize, ito : usize) -> Self {
match self {
MetaData::FloatArray (v) => MetaData::FloatArray (comp![ v[i] for i in ifrom..ito ]),
MetaData::IntArray (v) => MetaData::IntArray (comp![ v[i] for i in ifrom..ito ]),
MetaData::StringArray (v) => MetaData::StringArray (comp![ v[i].clone() for i in ifrom..ito ]),
MetaData::StringMatrix(v) => MetaData::StringMatrix(comp![ v[i].clone() for i in ifrom..ito ]),
MetaData::FloatMatrix (v) => MetaData::FloatMatrix (comp![ v[i].clone() for i in ifrom..ito ]),
MetaData::IntMatrix (v) => MetaData::IntMatrix (comp![ v[i].clone() for i in ifrom..ito ]),
MetaData::RangeArray (v) => MetaData::RangeArray (comp![ v[i].clone() for i in ifrom..ito ]),
}
}
pub fn subset(&self, indices : &[usize]) -> Self {
match self {
MetaData::FloatArray (v) => MetaData::FloatArray (comp![ v[*i] for i in indices ]),
MetaData::IntArray (v) => MetaData::IntArray (comp![ v[*i] for i in indices ]),
MetaData::StringArray (v) => MetaData::StringArray (comp![ v[*i].clone() for i in indices ]),
MetaData::StringMatrix(v) => MetaData::StringMatrix(comp![ v[*i].clone() for i in indices ]),
MetaData::FloatMatrix (v) => MetaData::FloatMatrix (comp![ v[*i].clone() for i in indices ]),
MetaData::IntMatrix (v) => MetaData::IntMatrix (comp![ v[*i].clone() for i in indices ]),
MetaData::RangeArray (v) => MetaData::RangeArray (comp![ v[*i].clone() for i in indices ]),
}
}
pub fn get_float(&self) -> Option<&Vec<f64>> {
match self {
MetaData::FloatArray(v) => Some(v),
_ => None
}
}
pub fn get_int(&self) -> Option<&Vec<i64>> {
match self {
MetaData::IntArray(v) => Some(v),
_ => None
}
}
pub fn get_str(&self) -> Option<&Vec<String>> {
match self {
MetaData::StringArray(v) => Some(v),
_ => None
}
}
pub fn get_range(&self) -> Option<&Vec<Range>> {
match self {
MetaData::RangeArray(v) => Some(v),
_ => None
}
}
pub fn get_float_mut(&mut self) -> Option<&mut Vec<f64>> {
match self {
MetaData::FloatArray(v) => Some(v),
_ => None
}
}
pub fn get_int_mut(&mut self) -> Option<&mut Vec<i64>> {
match self {
MetaData::IntArray(v) => Some(v),
_ => None
}
}
pub fn get_str_mut(&mut self) -> Option<&mut Vec<String>> {
match self {
MetaData::StringArray(v) => Some(v),
_ => None
}
}
pub fn get_range_mut(&mut self) -> Option<&mut Vec<Range>> {
match self {
MetaData::RangeArray(v) => Some(v),
_ => None
}
}
}
impl PartialEq for MetaData {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(MetaData::FloatArray (v), MetaData::FloatArray (w)) => v == w,
(MetaData::IntArray (v), MetaData::IntArray (w)) => v == w,
(MetaData::StringArray (v), MetaData::StringArray (w)) => v == w,
(MetaData::StringMatrix(v), MetaData::StringMatrix(w)) => v == w,
(MetaData::FloatMatrix (v), MetaData::FloatMatrix (w)) => v == w,
(MetaData::IntMatrix (v), MetaData::IntMatrix (w)) => v == w,
(MetaData::RangeArray (v), MetaData::RangeArray (w)) => v == w,
_ => false
}
}
}
#[derive(Clone, Debug)]
pub struct Meta {
pub meta_name: Vec<String>,
pub meta_data: Vec<MetaData>,
rows: usize,
}
impl Default for Meta {
fn default() -> Meta {
Self {
meta_name: Vec::new(),
meta_data: Vec::new(),
rows: 0,
}
}
}
impl Meta {
pub fn new(names: Vec<&str>, data: Vec<MetaData>) -> Result<Self, Box<dyn Error>> {
if names.len() != data.len() {
return Err(format!("Invalid parameters!").into());
}
let mut meta = Meta {
meta_name: Vec::new(),
meta_data: Vec::new(),
rows: 0,
};
for i in 0..names.len() {
meta.add(names[i], data[i].clone())?;
}
Ok(meta)
}
pub fn num_rows(&self) -> usize {
self.rows
}
pub fn num_cols(&self) -> usize {
self.meta_name.len()
}
pub fn append(&self, meta : &Meta) -> Result<Self, Box<dyn Error>> {
let n1 = self.num_rows();
let n2 = meta.num_rows();
let mut meta_name = Vec::new();
let mut meta_data = Vec::new();
for j in 0..self.num_cols() {
let meta_col1 = self.meta_data[j].clone();
let meta_col2 = meta.get_column(&meta.meta_name[j]);
if meta_col2.is_none() {
return Err(format!("Column {} not found in meta object", &meta.meta_name[j]).into())
}
let meta_col3 = meta_col1.concat(meta_col2.unwrap())?;
meta_name.push(self.meta_name[j].clone());
meta_data.push(meta_col3);
}
let meta = Meta {
meta_name: meta_name,
meta_data: meta_data,
rows: n1+n2,
};
Ok(meta)
}
pub fn add(&mut self, name: &str, data: MetaData) -> Result<(), Box<dyn Error>> {
let n = data.len();
if self.meta_name.len() > 0 {
if n != self.rows {
return Err(format!("Column '{}' has invalid length: expected length of '{}' but column has length '{}'", name, self.rows, n).into());
}
}
if self.meta_name.len() == 0 {
self.rows = n;
}
self.meta_name.push(String::from(name));
self.meta_data.push(data);
Ok(())
}
pub fn delete_meta(&mut self, name: &str) {
if let Some(index) = self.meta_name.iter().position(|x| x == name) {
self.meta_name.remove(index);
self.meta_data.remove(index);
}
}
pub fn rename_meta(&mut self, name_old: &str, name_new: &str) {
if name_old == name_new {
return;
}
if let Some(index) = self.meta_name.iter().position(|x| x == name_old) {
self.meta_name[index] = name_new.to_string();
}
}
pub fn get_column(&self, name: &str) -> Option<&MetaData> {
self.meta_name.iter().position(|x| x == name).map(|index| &self.meta_data[index])
}
pub fn get_column_int(&self, name: &str) -> Option<&Vec<i64>> {
let r = self.get_column(name)?;
r.get_int()
}
pub fn get_column_float(&self, name: &str) -> Option<&Vec<f64>> {
let r = self.get_column(name)?;
r.get_float()
}
pub fn get_column_str(&self, name: &str) -> Option<&Vec<String>> {
let r = self.get_column(name)?;
r.get_str()
}
pub fn get_column_range(&self, name: &str) -> Option<&Vec<Range>> {
let r = self.get_column(name)?;
r.get_range()
}
pub fn get_column_mut(&mut self, name: &str) -> Option<&mut MetaData> {
self.meta_name.iter().position(|x| x == name).map(move |index| &mut self.meta_data[index])
}
pub fn get_column_int_mut(&mut self, name: &str) -> Option<&mut Vec<i64>> {
let r = self.get_column_mut(name)?;
r.get_int_mut()
}
pub fn get_column_float_mut(&mut self, name: &str) -> Option<&mut Vec<f64>> {
let r = self.get_column_mut(name)?;
r.get_float_mut()
}
pub fn get_column_str_mut(&mut self, name: &str) -> Option<&mut Vec<String>> {
let r = self.get_column_mut(name)?;
r.get_str_mut()
}
pub fn get_column_range_mut(&mut self, name: &str) -> Option<&mut Vec<Range>> {
let r = self.get_column_mut(name)?;
r.get_range_mut()
}
pub fn slice(&self, ifrom : usize, ito : usize) -> Meta {
let n = ito-ifrom;
let m = self.meta_name.len();
let mut data = Vec::new();
for j in 0..m {
data.push(self.meta_data[j].slice(ifrom, ito));
}
Meta {
meta_name: self.meta_name.clone(),
meta_data: data,
rows: n,
}
}
pub fn subset(&self, indices: &[usize]) -> Meta {
let n = indices.len();
let m = self.meta_name.len();
let mut data = Vec::new();
for j in 0..m {
data.push(self.meta_data[j].subset(indices));
}
Meta {
meta_name: self.meta_name.clone(),
meta_data: data,
rows: n,
}
}
pub fn sort(&self, name: &str, reverse: bool) -> Result<Self, Box<dyn Error>> {
let mut indices: Vec<usize> = (0..self.rows).collect();
if reverse {
match self.get_column(name).unwrap() {
MetaData::StringArray(v) => indices.sort_by(|&i, &j| v[j].cmp(&v[i])),
MetaData::FloatArray (v) => indices.sort_by(|&i, &j| v[j].partial_cmp(&v[i]).unwrap()),
MetaData::IntArray (v) => indices.sort_by(|&i, &j| v[j].cmp(&v[i])),
_ => ()
}
}
else {
match self.get_column(name).unwrap() {
MetaData::StringArray(v) => indices.sort_by(|&i, &j| v[i].cmp(&v[j])),
MetaData::FloatArray (v) => indices.sort_by(|&i, &j| v[i].partial_cmp(&v[j]).unwrap()),
MetaData::IntArray (v) => indices.sort_by(|&i, &j| v[i].cmp(&v[j])),
_ => ()
}
}
Ok(self.subset(&indices))
}
pub fn iter(&self) -> impl Iterator<Item = (&String, &MetaData)> {
self.meta_name.iter().zip(self.meta_data.iter())
}
}
impl PartialEq for Meta {
fn eq(&self, other: &Self) -> bool {
if self.num_cols() != other.num_cols() {
return false;
}
if self.num_rows() != other.num_rows() {
return false;
}
for j in 0..self.num_cols() {
let name = &self.meta_name[j];
let meta_col1 = self.meta_data[j].clone();
let meta_col2 = other.get_column(name);
if meta_col2.is_none() {
return false;
}
if meta_col1 != *meta_col2.unwrap() {
return false;
}
}
true
}
}
impl fmt::Display for Meta {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.pad(&format!("{}", self.format_pretty(10, false).unwrap()))
}
}