Skip to content

Instantly share code, notes, and snippets.

@Pzixel Pzixel/fixed.rs
Last active May 7, 2019

Embed
What would you like to do?
#![allow(unused)]
use std::collections::{HashMap, HashSet};
use serde_json::Value;
use std::fs::File;
use std::io::BufReader;
use std::marker::PhantomData;
use std::fmt;
use serde::{Deserialize, Deserializer};
use serde::de::{self, Visitor, SeqAccess};
use std::str::FromStr;
const FILE_BUFFER_SIZE: usize = 50000;
//source data
#[derive(Default)]
struct DebtRec {
company: String,
phones: Vec<String>,
debt: f64,
}
//result data
#[derive(Default)]
struct Debtor {
companies: HashSet<String>,
phones: HashSet<String>,
debt: f64,
}
#[derive(Default)]
struct Debtors {
all: Vec<Debtor>,
index_by_phone: HashMap<String, usize>,
}
impl<'de> Visitor<'de> for DebtorsVisitor
{
type Value = Debtors;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a nonempty sequence of numbers")
}
fn visit_seq<S>(self, mut seq: S) -> Result<Self::Value, S::Error>
where
S: SeqAccess<'de>,
{
let mut deptors = Debtors::default();
// Update the max while there are additional values.
while let Some(debt) = seq.next_element::<Value>()? {
process_object(&debt, &mut deptors);
}
Ok(deptors)
}
}
struct DebtorsVisitor;
impl<'de> Deserialize<'de> for Debtors {
fn deserialize<D>(deserializer: D) -> Result<Debtors, D::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_seq(DebtorsVisitor)
}
}
fn main() {
let filename = std::env::args().nth(1).expect("filename");
let tbegin = std::time::SystemTime::now();
let res = get_res(&filename);
for (di, d) in res.all.iter().enumerate() {
println!("-------------------------------");
println!("#{}: debt: {}", di, &d.debt);
println!("companies: {:?}\nphones: {:?}", &d.companies, &d.phones);
}
}
fn get_res(path: &str) -> Debtors {
let file = File::open(path).unwrap();
let reader = BufReader::with_capacity(FILE_BUFFER_SIZE, file);
let out: Debtors = serde_json::from_reader(reader).unwrap();
out
}
fn process_object(o: &Value, res: &mut Debtors) {
let dr = extract_data(o);
//println!("{} - {:?} - {}", &dr.company, &dr.phones, &dr.debt,);
let debtor_index = dr.phones.iter().filter_map(|p| res.index_by_phone.get(p).cloned()).next();
let i = debtor_index.unwrap_or_else(|| {
res.all.push(Debtor::default());
res.all.len() - 1
});
let d = &mut res.all[i];
d.companies.insert(dr.company);
for p in &dr.phones {
d.phones.insert(p.to_owned());
res.index_by_phone.insert(p.to_owned(), i);
}
d.debt += dr.debt;
}
fn val2str(v: &Value) -> String {
match v {
Value::String(vs) => vs.to_owned(), //to avoid additional quotes
_ => v.to_string(),
}
}
fn extract_data(o: &Value) -> DebtRec {
let mut dr = DebtRec::default();
dr.company = match &o["company"] {
Value::Object(c1) => match &c1["name"] {
Value::String(c2) => c2.to_owned(),
c => val2str(c),
},
c => val2str(c),
};
match &o["phones"] {
Value::Null => {}
Value::Array(pp) => dr.phones.extend(pp.iter().map(|p| val2str(p))),
pp => dr.phones.push(val2str(&pp)),
}
let p = &o["phone"];
if !p.is_null() {
dr.phones.push(val2str(&p));
}
dr.debt = match &o["debt"] {
Value::Number(d) => d.as_f64().unwrap_or(0.0),
Value::String(d) => d.parse().unwrap_or(0.0),
_ => 0.0,
};
dr
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.