use std::error::Error;
use std::fmt::Display;
use std::fs::File;
use std::io::{BufRead, BufReader, Write};
use std::str::FromStr;
use crate::Matrix;
pub fn load_matrix_from_csv<T: Default + Copy + FromStr>(path: &str, separator: &str) -> Result<Matrix<T>, Box<dyn Error>> where T: Default + Copy + FromStr, <T as FromStr>::Err: 'static, <T as FromStr>::Err: Error {
let file = File::open(path)?;
let reader = BufReader::new(file);
let data: Vec<T> = Vec::new();
let mut matrix = Matrix::new(data, (0, 0))?;
let mut header = true;
for line in reader.lines() {
if header {
header = false;
continue;
}
let line_tmp = line?;
let split: Vec<&str> = line_tmp.split(separator).collect();
let mut row: Vec<T> = Vec::new();
for i in 0..split.len() {
let value = split[i].parse::<T>()?;
row.push(value);
}
matrix.add_row_from_vec(matrix.shape.0, row)?;
}
Ok(matrix)
}
pub fn load_matrix_from_csv_columns<T: Default + Copy + FromStr>(path: &str, separator: &str, columns: Vec<String>) -> Result<Matrix<T>, Box<dyn Error>> where T: Default + Copy + FromStr, <T as FromStr>::Err: 'static, <T as FromStr>::Err: Error {
let file = File::open(path)?;
let reader = BufReader::new(file);
let data: Vec<T> = Vec::new();
let mut matrix = Matrix::new(data, (0, 0))?;
let mut header = true;
let mut index_columns: Vec<usize> = Vec::new();
for line in reader.lines() {
let line_tmp = line?;
if header {
header = false;
index_columns = get_columns_headers_index(&columns, line_tmp, separator);
continue;
}
let split: Vec<&str> = line_tmp.split(separator).collect();
let mut row: Vec<T> = Vec::new();
for i in 0..split.len() {
if !index_columns.contains(&i) {
continue;
}
let value = split[i].parse::<T>()?;
row.push(value);
}
matrix.add_row_from_vec(matrix.shape.0, row)?;
}
Ok(matrix)
}
pub fn load_matrix_from_csv_excluding_columns<T: Default + Copy + FromStr>(path: &str, separator: &str, columns: Vec<String>) -> Result<Matrix<T>, Box<dyn Error>> where T: Default + Copy + FromStr, <T as FromStr>::Err: 'static, <T as FromStr>::Err: Error {
let file = File::open(path)?;
let reader = BufReader::new(file);
let data: Vec<T> = Vec::new();
let mut matrix = Matrix::new(data, (0, 0))?;
let mut header = true;
let mut index_columns: Vec<usize> = Vec::new();
for line in reader.lines() {
let line_tmp = line?;
if header {
header = false;
index_columns = get_columns_headers_index(&columns, line_tmp, separator);
continue;
}
let split: Vec<&str> = line_tmp.split(separator).collect();
let mut row: Vec<T> = Vec::new();
for i in 0..split.len() {
if index_columns.contains(&i) {
continue;
}
let value = split[i].parse::<T>()?;
row.push(value);
}
matrix.add_row_from_vec(matrix.shape.0, row)?;
}
Ok(matrix)
}
fn get_columns_headers_index(columns: &Vec<String>, header: String, separator: &str) -> Vec<usize> {
let mut index_columns: Vec<usize> = Vec::new();
let split: Vec<&str> = header.split(separator).collect();
for i in 0..split.len() {
for j in 0..columns.len() {
if split[i] == columns[j] {
index_columns.push(i);
}
}
}
index_columns
}
pub fn write_matrix_to_csv<T: Display>(matrix: &Matrix<T>, path: &str, separator: &str) -> Result<(), Box<dyn Error>> {
let mut file = File::create(path)?;
let mut header = String::new();
for i in 0..matrix.shape.1 {
header.push_str(&format!("col_{}", i));
if i != matrix.shape.1 - 1 {
header.push_str(separator);
}
}
header.push_str("\n");
file.write_all(header.as_bytes())?;
for i in 0..matrix.shape.0 {
let mut row = String::new();
for j in 0..matrix.shape.1 {
row.push_str(&format!("{}", matrix[i][j]));
if j != matrix.shape.1 - 1 {
row.push_str(separator);
}
}
row.push_str("\n");
file.write_all(row.as_bytes())?;
}
Ok(())
}
pub fn write_matrix_to_csv_with_headers<T: Display>(matrix: &Matrix<T>, path: &str, separator: &str, headers: Vec<String>) -> Result<(), Box<dyn Error>> {
if headers.len() != matrix.shape.1 {
return Err("The number of headers does not match the number of columns in the matrix.".into());
}
let mut file = File::create(path)?;
let mut header = String::new();
for i in 0..matrix.shape.1 {
header.push_str(&format!("{}", headers[i]));
if i != matrix.shape.1 - 1 {
header.push_str(separator);
}
}
header.push_str("\n");
file.write_all(header.as_bytes())?;
for i in 0..matrix.shape.0 {
let mut row = String::new();
for j in 0..matrix.shape.1 {
row.push_str(&format!("{}", matrix[i][j]));
if j != matrix.shape.1 - 1 {
row.push_str(separator);
}
}
row.push_str("\n");
file.write_all(row.as_bytes())?;
}
Ok(())
}