- 
      
 - 
        
Save steveklabnik/ad0a33acc82e21ca3f763e4278ad31a5 to your computer and use it in GitHub Desktop.  
| use std::env; | |
| use std::io; | |
| use std::io::prelude::*; | |
| use std::fs::File; | |
| #[derive(Debug)] | |
| enum Error { | |
| Io(io::Error), | |
| Program(&'static str), | |
| } | |
| impl From<io::Error> for Error { | |
| fn from(e: io::Error) -> Error { | |
| Error::Io(e) | |
| } | |
| } | |
| impl From<&'static str> for Error { | |
| fn from(e: &'static str) -> Error { | |
| Error::Program(e) | |
| } | |
| } | |
| fn main() { | |
| let mut args = env::args(); | |
| // skip the program name | |
| args.next().unwrap(); | |
| let filename = args.next().unwrap(); | |
| let column_name = args.next().unwrap(); | |
| let replacement = args.next().unwrap(); | |
| let output_filename = args.next().unwrap(); | |
| let csv_data = load_csv(&filename).unwrap(); | |
| let modified_data = replace_column(csv_data, &column_name, &replacement).unwrap(); | |
| write_csv(&modified_data, &output_filename).unwrap(); | |
| } | |
| fn load_csv(filename: &str) -> Result<String, Error> { | |
| let mut f = File::open(filename)?; | |
| let mut buffer = String::new(); | |
| f.read_to_string(&mut buffer)?; | |
| if buffer.is_empty() { | |
| return Err("input file missing")? | |
| } | |
| Ok(buffer) | |
| } | |
| fn replace_column(data: String, column: &str, replacement: &str) -> Result<String, Error> { | |
| let mut lines = data.lines(); | |
| let columns = lines.next().unwrap(); | |
| let columns: Vec<&str> = columns.split(',').collect(); | |
| let column_number = columns.iter().position(|&e| e == column); | |
| let column_number = match column_number { | |
| Some(column) => column, | |
| None => Err("column name doesn’t exist in the input file")? | |
| }; | |
| let mut result = String::with_capacity(data.capacity()); | |
| result.push_str(&columns.join(",")); | |
| result.push('\n'); | |
| for line in lines { | |
| let mut records: Vec<&str> = line.split(',').collect(); | |
| records[column_number] = replacement; | |
| result.push_str(&records.join(",")); | |
| result.push('\n'); | |
| } | |
| Ok(result) | |
| } | |
| fn write_csv(data: &str, filename: &str) -> Result<(), Error> { | |
| let mut buffer = File::create(filename)?; | |
| buffer.write_all(data.as_bytes())?; | |
| Ok(()) | |
| } | 
Looks a lot more readable than the winning C++17 entry
Nice, yet I have to nitpick that the winning C++ entry does not load the entire input file into memory. Wrapping the file into a std::io::BufReader instead of saving it to a string would do the trick, since BufRead also exposes a lines() iterator.
I like some aspects of the C++ version more, so I decided to combine them into my own version. Also there is a problem, that the winning entry does not respect the rule In both cases, there shouldn’t be any output file generated.. I decided to obey this rule, although it makes the code less nice, because of the split of the get_file_handlers function.
https://gist.github.com/msehnout/6b6a964b4ce87df104f67aefdcb0585c
@msehnout: I totally agree that for big csv it could a problem to read everything into memory. Another issue could be: not necessary mallocs inside the iteratation over the lines. Actually, there is no need for creating any temporary vectors or strings at all: https://gist.github.com/boxdot/8abd5eccec95dd74d0a35d33463ae53b
I was too lazy to define From impls, which definitely a better approach than using String as universal error wrapper.
Beautiful !!!