Skip to content

Instantly share code, notes, and snippets.

@lights0123
Created May 3, 2020 17:32
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lights0123/23b3cded6ee039db2ce0ac5c8677a37c to your computer and use it in GitHub Desktop.
Save lights0123/23b3cded6ee039db2ce0ac5c8677a37c to your computer and use it in GitHub Desktop.
//! # 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