improve ballot parse function

This commit is contained in:
Jay Robson 2025-05-03 21:40:08 +10:00
parent 4645cb31ee
commit 99724e5504
3 changed files with 39 additions and 42 deletions

View File

@ -22,54 +22,47 @@ pub struct Ballot {
}
impl Ballot {
pub fn parse_rows<T: std::io::BufRead>(csv: quick_csv::Csv<T>, header: &Header) -> Result<Vec<Ballot>, Box<dyn std::error::Error>> {
let mut ballots = Vec::<Self>::new();
pub fn parse(row: quick_csv::Row, header: &Header) -> Result<Ballot, Box<dyn std::error::Error>> {
let mut cols = row.columns()?;
let (state, division, collection_point, collection_point_id, batch_id, paper_id) = cols.next_tuple().ok_or("Missing columns")?;
let cols = cols.collect_vec();
let mut votes: Vec<Option<usize>>;
let ty: BallotType;
let col_filter = |(index, place): (usize, &str)| match place.parse::<usize>() {
Ok(v) => Some((index, v - 1)),
Err(_) => None,
};
for result in csv {
let row = result?;
let mut cols = row.columns()?;
let (state, division, collection_point, collection_point_id, batch_id, paper_id) = cols.next_tuple().ok_or("Missing columns")?;
let cols = cols.collect_vec();
let mut votes: Vec<Option<usize>>;
let ty: BallotType;
// below the line votes
if cols.len() > header.parties.len() {
ty = BallotType::Candidate;
votes = vec![None; header.candidates.len()];
for (col_id, place) in cols.iter().copied().skip(header.parties.len()).take(header.candidates.len()).enumerate().filter_map(col_filter) {
votes[place] = Some(col_id);
}
// below the line votes
if cols.len() > header.parties.len() {
ty = BallotType::Candidate;
votes = vec![None; header.candidates.len()];
for (col_id, place) in cols.iter().copied().skip(header.parties.len()).take(header.candidates.len()).enumerate().filter_map(col_filter) {
votes[place] = Some(col_id);
}
// above the line votes
else {
ty = BallotType::Party;
votes = vec![None; header.parties.len()];
for (col_id, place) in cols.iter().copied().take(header.parties.len()).enumerate().filter_map(col_filter) {
votes[place] = Some(col_id);
}
}
ballots.push(Ballot {
state: state.to_owned(),
division: division.to_owned(),
collection_point: collection_point.to_owned(),
collection_point_id: collection_point_id.parse()?,
batch_id: batch_id.parse()?,
paper_id: paper_id.parse()?,
votes: votes.iter().copied().filter_map(|v| v).collect(),
ty,
});
}
Ok(ballots)
// above the line votes
else {
ty = BallotType::Party;
votes = vec![None; header.parties.len()];
for (col_id, place) in cols.iter().copied().take(header.parties.len()).enumerate().filter_map(col_filter) {
votes[place] = Some(col_id);
}
}
Ok(Ballot {
state: state.to_owned(),
division: division.to_owned(),
collection_point: collection_point.to_owned(),
collection_point_id: collection_point_id.parse()?,
batch_id: batch_id.parse()?,
paper_id: paper_id.parse()?,
votes: votes.iter().copied().filter_map(|v| v).collect(),
ty,
})
}
}

View File

@ -10,7 +10,11 @@ pub struct Counter {
impl Counter {
pub fn new<T: std::io::BufRead>(mut csv: quick_csv::Csv<T>) -> Result<Self, Box<dyn std::error::Error>> {
let header = Header::parse(csv.next().ok_or("csv header missing")??)?;
let ballots = Ballot::parse_rows(csv, &header)?;
let mut ballots = Vec::new();
for row in csv {
ballots.push(Ballot::parse(row?, &header)?);
}
Ok(Counter {
header,
@ -18,5 +22,6 @@ impl Counter {
})
}
}

View File

@ -1,8 +1,7 @@
use std::env;
use ballot::{Ballot, BallotType};
use ballot::BallotType;
use counter::Counter;
use header::Header;
pub mod candidate;
pub mod ballot;