Data merge... lookup in rust

Hi..

I am new to rust and trying to do the following..
I have two csv files. one with roll no and names of students and other with roll no and marks of the same students(not in the same order)
I would like to take in data from both files and use roll no as common field and merge both.

rollno.   name
  7         Chris
  2         rob
  4         tom
  3         Jim


rollno.    physics.  chem   bio
4             78           89       82
3             81           98       94
7             87           79       95
2             81           96       84

I want to merge both the above csv files and perform some calculations and write the output file to a csv as below.

    roll_no	physics	chem	bio	names	total	   avg
    4	          78	         89	        82	  tom	249	    83
    3	          81	         98	        94	  jim	        273	    91
    7	          87	         79	        95	  chris	261	    87
    2	          81	         96	        84	  rob	        261	    87

Please help / guide ..

You are looking for the csv and serde crates to read the data. First you will want to create some structs like these to hold your data. Note the use of Deserialize for input and Serialize for output types.

use serde::{Serialize, Deserialize};

#[derive(Debug, Deserialize)]
struct NameRecord {
    roll_no: u32,
    name: String,
}

#[derive(Debug, Deserialize)]
struct MarksRecord {
    roll_no: u32,
    physics: u32,
    chem: u32,
    bio: u32,
}

#[derive(Debug, Serialize)]
struct SummaryRecord {
    roll_no: u32,
    physics: u32,
    chem: u32,
    bio: u32,
    names: String,
    total: u32,
    avg: u32,
}

Then you will want to first read all of the names into memory.

use std::collections::HashMap;

// We store the names in a HashMap
let names = HashMap::new();

// Start by reading in names.
let mut rdr = csv::Reader::from_path("names.csv");
for result in rdr.deserialize() {
    // Specify NameRecord so it knows what data to expect.
    let record: NameRecord = result.expect("Invalid name record");
    names.insert(record.roll_no, record.name);
}

We can then read through the other file to get their marks. As we read through them, we can also write out the result.

// Open both a reader and writer.
let mut rdr = csv::Reader::from_path("marks.csv");
let mut writer = csv::Writer::from_path("summary.csv");

for result in rdr.deserialize() {
    // Specify MarksRecord so it knows what data to expect.
    let record: MarksRecord = result.expect("Invalid mark record");
    
    // look up the name
    let name = names.get(&record.roll_no).expect("Name not found");
    
    let total = record.physics + record.chem + record.bio;
    let avg = total / 3;
    
    // Write the line to the summary file.
    writer.serialize(SummaryRecord {
        roll_no: record.roll_no,
        physics: record.physics,
        chem: record.chem,
        bio: records.bio,
        names: name.to_string(),
        total,
        avg,
    }).expect("Failed to write record");
}

Note that I have not tested whether any of this code compiles. Check also the csv tutorial out.

Hey.. Thanks Alice.. will do.. This is really helpful!

1 Like