use std::fs::OpenOptions;
use csv::{ReaderBuilder, Writer};
pub fn read_csv_file(file_path: &str, has_headers: bool) -> Vec<Vec<String>> {
let mut reader = ReaderBuilder::new()
.has_headers(has_headers)
.from_path(file_path)
.expect("Failed to open CSV file");
let mut records = Vec::new();
for result in reader.records() {
let record = result.expect("Failed to read a record");
records.push(record.iter().map(|s| s.to_string()).collect());
}
records
}
pub fn write_csv_file(file_path: &str, data: Vec<Vec<String>>) {
let mut writer = Writer::from_path(file_path).expect("Failed to create CSV writer");
for row in data {
writer.write_record(&row).expect("Failed to write a record");
}
writer.flush().expect("Failed to flush writer");
}
pub fn append_csv_file(file_path: &str, data: Vec<Vec<String>>) {
let file = OpenOptions::new()
.append(true)
.create(true)
.open(file_path)
.expect("Failed to open or create file");
let mut writer = Writer::from_writer(file);
for row in data {
writer.write_record(&row).expect("Failed to write a record");
}
writer.flush().expect("Failed to flush writer");
}
pub fn show_csv_data(records: &Vec<Vec<String>>) {
for record in records {
println!("{:?}", record);
}
}
pub fn is_found_data(records: &[Vec<String>], find_data: &str) -> bool {
for record in records.iter() {
for field in record.iter() {
if field == find_data {
return true;
}
}
}
false
}
pub fn find_data(records: &[Vec<String>], find_data: &str) -> Vec<(usize, usize)> {
let mut results = Vec::new();
for (row_no, record) in records.iter().enumerate() {
for (col_no, field) in record.iter().enumerate() {
if field == find_data {
results.push((row_no + 1, col_no + 1)); }
}
}
results }
pub fn retrieve_data_by_position(
records: &[Vec<String>],
row_no: usize,
column_no: usize,
) -> String {
if row_no == 0 || column_no == 0 {
println!("Row and column indices must be 1 or greater");
return String::new();
}
if row_no > records.len() || column_no > records[0].len() {
println!("Row and column indices must be within the valid range");
return String::new();
}
records[row_no - 1][column_no - 1].to_string()
}
pub fn retrieve_data_by_index(
records: &[Vec<String>],
row_index: usize,
column_index: usize,
) -> String {
if row_index >= records.len() || column_index >= records[0].len() {
println!("Row and column indices must be within the valid range");
return String::new();
}
records[row_index][column_index].to_string()
}
pub fn show_csv_size(records: &[Vec<String>]) -> (usize, usize) {
let row_count = records.len();
let col_count = if row_count > 0 { records[0].len() } else { 0 };
(row_count, col_count)
}
pub fn remove_data_by_row_no(records: &[Vec<String>], row_no_list: &[usize]) -> Vec<Vec<String>> {
if row_no_list.contains(&0) {
println!("Index 0 is invalid");
return records.to_vec();
}
let mut row_no_list: Vec<usize> = row_no_list.iter().map(|&n| n - 1).collect();
row_no_list.sort_unstable_by(|a, b| b.cmp(a));
let mut new_records = records.to_vec();
for &row_no in &row_no_list {
if row_no < records.len() {
new_records.remove(row_no);
} else {
println!("Index {} out of bounds", row_no + 1);
return records.to_vec();
}
}
new_records
}
pub fn remove_data_by_column_no(
records: &[Vec<String>],
column_no_list: &[usize],
) -> Vec<Vec<String>> {
if column_no_list.contains(&0) {
println!("Index 0 is invalid");
return records.to_vec();
}
if column_no_list.contains(&(records[0].len() + 1)) {
println!("Index {} is out of bounds", records[0].len() + 1);
return records.to_vec();
}
let mut column_no_list: Vec<usize> = column_no_list.iter().map(|&n| n - 1).collect();
column_no_list.sort_unstable_by(|a, b| b.cmp(a));
records
.iter()
.map(|record| {
let mut record = record.to_vec();
for &col_no in &column_no_list {
if col_no < record.len() {
record.remove(col_no);
}
}
record
})
.collect()
}
pub fn select_data_by_row_no(records: &[Vec<String>], row_no_list: &[usize]) -> Vec<Vec<String>> {
let mut selected_records = Vec::new();
if row_no_list.contains(&0) {
println!("Index 0 is invalid");
return records.to_vec();
}
if row_no_list.contains(&(records[0].len() + 1)) {
println!("Index {} is out of bounds", records[0].len() + 1);
return records.to_vec();
}
for &row_no in row_no_list {
let index = row_no - 1;
if index < records.len() {
selected_records.push(records[index].to_vec());
}
}
selected_records
}
pub fn select_data_by_column_no(
records: &[Vec<String>],
column_no_list: &[usize],
) -> Vec<Vec<String>> {
if column_no_list.contains(&0) {
println!("Index 0 is invalid");
return records.to_vec();
}
if column_no_list.contains(&(records[0].len() + 1)) {
println!("Index {} is out of bounds", records[0].len() + 1);
return records.to_vec();
}
let mut selected_records = Vec::new();
for record in records.iter() {
let mut selected_row = Vec::new();
for &col_no in column_no_list {
let index = col_no - 1;
if index < record.len() {
selected_row.push(record[index].to_string());
} else {
println!("Index {} out of bounds", col_no);
}
}
selected_records.push(selected_row);
}
selected_records
}
pub fn replace_data_at_row_no(
records: &[Vec<String>],
row_no: usize,
replace_data: &[String],
) -> Vec<Vec<String>> {
if row_no == 0 {
println!("Row number must be greater than 0");
return records.to_vec();
}
let index = row_no - 1;
if index < records.len() {
let mut new_records = records.to_vec();
new_records[index] = replace_data.to_vec();
new_records
} else {
println!("Index {} out of bounds", row_no);
records.to_vec()
}
}
pub fn replace_data_at_column_no(
records: &[Vec<String>],
column_no: usize,
replace_data: &[String],
) -> Vec<Vec<String>> {
if column_no == 0 {
println!("Column number must be greater than 0");
return records.to_vec();
}
let index = column_no - 1;
records
.iter()
.enumerate()
.map(|(i, record)| {
if index < record.len() {
let mut new_record = record.to_vec();
new_record[index] = replace_data[i].to_string();
new_record
} else {
println!("Index {} out of bounds", column_no);
record.to_vec()
}
})
.collect()
}
pub fn transpose_data(records: &[Vec<String>]) -> Vec<Vec<String>> {
let mut transposed = Vec::new();
let row_count = records.len();
let col_count = if row_count > 0 { records[0].len() } else { 0 };
for col in 0..col_count {
let mut new_row = Vec::with_capacity(row_count);
for row in records {
new_row.push(row[col].to_owned());
}
transposed.push(new_row);
}
transposed
}
pub fn insert_data_before_row(
records: &[Vec<String>],
row_no: usize,
insert_data: &[String],
) -> Vec<Vec<String>> {
if row_no == 0 {
println!("Row number must be greater than 0");
return records.to_vec();
}
if row_no > records.len() {
println!("Row number {} is out of bounds", row_no);
return records.to_vec();
}
if let Some(index) = row_no.checked_sub(1) {
if index <= records.len() {
let mut new_records = records.to_vec();
new_records.insert(index, insert_data.to_vec());
new_records
} else {
println!("Row number {} is out of bounds", row_no);
records.to_vec()
}
} else {
println!("Row number must be greater than 0");
records.to_vec()
}
}
pub fn insert_data_before_column(
records: &[Vec<String>],
column_no: usize,
insert_data: &[String],
) -> Vec<Vec<String>> {
if column_no == 0 {
println!("Row number must be greater than 0");
return records.to_vec();
}
if column_no > records.len() {
println!("Row number {} is out of bounds", column_no);
return records.to_vec();
}
let index = column_no.checked_sub(1).unwrap_or_else(|| {
println!("Column number must be greater than or equal to 1");
0 });
records
.iter()
.enumerate()
.map(|(i, record)| {
if index > record.len() {
println!(
"Column number {} is out of bounds for row {}",
column_no,
i + 1
);
}
let mut new_record = Vec::with_capacity(record.len() + 1);
new_record.extend_from_slice(&record[..index]);
new_record.push(insert_data[i].to_owned());
new_record.extend_from_slice(&record[index..]);
new_record
})
.collect()
}
pub fn append_data_row(records: &[Vec<String>], append_data: &[String]) -> Vec<Vec<String>> {
let mut new_records = records.to_vec();
new_records.push(append_data.to_vec());
new_records
}
pub fn append_data_column(records: &[Vec<String>], append_data: &[String]) -> Vec<Vec<String>> {
if records.len() != append_data.len() {
println!(
"append_data length ({}) does not match number of rows ({})",
append_data.len(),
records.len()
);
return records.to_vec();
}
records
.iter()
.zip(append_data)
.map(|(record, value)| {
let mut new_record = record.to_vec();
new_record.push(value.to_owned());
new_record
})
.collect()
}
pub fn flatten_csv_data(data: &[Vec<String>]) -> Vec<String> {
data.iter().map(|row| row.join(",")).collect()
}
pub fn convert_string_data_to_csv_data(data: &[Vec<String>]) -> Vec<Vec<String>> {
let mut result: Vec<Vec<String>> = Vec::new();
for row in data.iter() {
for val in row.iter() {
let p: Vec<&str> = val.split_whitespace().collect();
result.push(p.into_iter().map(|s| s.to_string()).collect());
}
}
result
}