-
-
Save lights0123/23b3cded6ee039db2ce0ac5c8677a37c to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//! # CSV Sorter | |
//! | |
//! This program reads in a CSV composed of information about people, such as | |
//! names and addresses. It then stores each entry into a struct, and those | |
//! structs into a vector. The vector is sorted by last name (or first, if | |
//! last names are identical) and the newly sorted data is written to an | |
//! output file. | |
use std::cmp::Ordering; | |
use std::env; | |
use std::fs::File; | |
use std::io::{BufRead, BufReader, BufWriter, Write}; | |
use std::path::PathBuf; | |
use std::process; | |
/// Person struct to hold relevant data | |
#[derive(Debug, PartialEq, Eq)] | |
struct Person { | |
first_name: String, | |
last_name: String, | |
street: String, | |
city: String, | |
state: String, | |
zip_code: String, | |
} | |
impl Ord for Person { | |
fn cmp(&self, other: &Self) -> Ordering { | |
( | |
self.last_name.to_lowercase(), | |
self.first_name.to_lowercase(), | |
) | |
.cmp(&( | |
other.last_name.to_lowercase(), | |
other.first_name.to_lowercase(), | |
)) | |
} | |
} | |
impl PartialOrd for Person { | |
fn partial_cmp(&self, other: &Self) -> Option<Ordering> { | |
Some(self.cmp(other)) | |
} | |
} | |
/// | |
/// Processes command-line arguments | |
/// | |
/// # Description | |
/// This function processes the passed-in command line arguments and attempts | |
/// to open and create valid input/output files from the names given. | |
/// | |
/// # Arguments | |
/// * `args` - A string array of command-line arguments. | |
/// | |
/// # Returns | |
/// * A tuple of the input file and output file if they are found, else errors. | |
/// | |
fn arg_parser(args: &[String]) -> Result<(File, File), &'static str> { | |
// Exit if too many or too few arguments were passed | |
if args.len() != 3 { | |
return Err("Usage: 'cargo run [input file] [output file]"); | |
} | |
// Get the input file | |
let input_file = File::open(PathBuf::from("src").join(&args[1])).expect("Couldn't open file"); | |
let output_file = | |
File::create(PathBuf::from("src").join(&args[2])).expect("Couldn't create file"); | |
// Return both files as a tuple | |
Ok((input_file, output_file)) | |
} | |
/// | |
/// Builds a list of Person structs | |
/// | |
/// # Description | |
/// This function reads the input file line by line and creates a Person | |
/// struct based on the line's contents. It then adds that struct to a vector | |
/// and repeats for every line in the file. The final vector contains every | |
/// Person struct read in from the file. | |
/// | |
/// # Returns | |
/// * A vector of type Person containing all Person structs from the file. | |
fn build_person_vec(reader: &mut impl BufRead) -> Vec<Person> { | |
let mut person_vec: Vec<Person> = Vec::new(); | |
for line in reader.lines() { | |
let line = line.unwrap(); | |
let mut data = line.split(',').map(|s| s.trim()); | |
let p = Person { | |
first_name: String::from(data.next().unwrap()), | |
last_name: String::from(data.next().unwrap()), | |
street: String::from(data.next().unwrap()), | |
city: String::from(data.next().unwrap()), | |
state: String::from(data.next().unwrap()), | |
zip_code: String::from(data.next().unwrap()), | |
}; | |
person_vec.push(p); | |
} | |
person_vec | |
} | |
/// | |
/// Writes data to the output file | |
/// | |
/// Writes all Person structs to the output file, catching errors if the file | |
/// is not available to be written to. | |
fn write_to_file(person_vec: &[Person], output_file: &mut impl Write) { | |
for p in person_vec { | |
let info = format!( | |
"{}, {}, {}, {}, {}, {}\n", | |
p.first_name, p.last_name, p.street, p.city, p.state, p.zip_code | |
); | |
output_file | |
.write_all(info.as_bytes()) | |
.expect("Couldn't write to file"); | |
} | |
} | |
fn main() { | |
let args: Vec<String> = env::args().collect(); | |
// Get the input and output files | |
let (input_file, output_file) = arg_parser(&args).unwrap_or_else(|err| { | |
eprintln!("\nError: {}", err); | |
process::exit(1); | |
}); | |
let mut person_vec = build_person_vec(&mut BufReader::new(&input_file)); | |
person_vec.sort(); | |
write_to_file(&person_vec, &mut BufWriter::new(output_file)); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment