I want to learn rust-lang by solving some algorithm problems.
Unfortunately, reading inputs in Rust is not as convenient as in C++ or Python. Especially, I like to read the inputs from file while I am testing or debugging.
For example, in C++:
freopen("in.txt", "r", stdin); // comment out this line when submit it, that's all
int N;
cin >> N;
So I wrote the following codes. It works, but it is tedious and not elegant(?)
Any suggestions would be appreciated. Thank you and sorry for my poor English.
use std::io::{self, BufRead, BufReader};
use std::fs::File;
use std::collections::HashMap;
struct Scan<'a, T: BufRead + 'a> {
cur_pos: usize, // position of cur_line
cur_line: Option<String>, // current none blank line
reader: &'a mut T
}
impl<'a, T: BufRead + 'a> Scan<'a, T> {
fn new(buf: &'a mut T) -> Self {
Scan {
cur_pos: 0,
cur_line: None,
reader: buf
}
}
fn next_line(&mut self) {
let mut line = String::new();
'outer: loop {
self.reader.read_line(&mut line).expect("read error");
for ch in line.chars().next() {
if !ch.is_whitespace() {
break 'outer;
}
}
}
self.cur_pos = 0;
self.cur_line = Some(line.trim().to_string())
}
fn skip_whitespaces(&mut self) {
loop {
if self.cur_line.is_none() || self.cur_pos == self.cur_line.as_ref().unwrap().len() {
self.next_line();
}
if let Some(s) = self.cur_line.as_ref() {
// I'm trying to move to the next none whitespace char
// this part is tedious, In C++, I can write come code like:
// while (this->cur_pos < this->cur_line.size() && iswspace(this->cur_line[this->cur_pos]) { this->cur_pos++; }
// but I need to write (let ch = ...) twice here, any suggestions?
let ch = s.as_bytes()[self.cur_pos] as char;
while self.cur_pos < self.cur_line.as_ref().unwrap().len() && ch.is_whitespace() {
self.cur_pos += 1;
let ch = s.as_bytes()[self.cur_pos] as char;
}
if self.cur_pos < self.cur_line.as_ref().unwrap().len() {
break;
}
}
}
}
fn next_char(&mut self) -> char {
self.skip_whitespaces();
self.cur_pos += 1;
self.cur_line.as_ref().unwrap().as_bytes()[self.cur_pos-1] as char
}
fn next_string(&mut self) -> String {
self.skip_whitespaces();
let mut ret= String::new();
if let Some(s) = self.cur_line.as_ref() {
// need improvement here too!
// how to put the ch.is_whitespace into while conditions
while self.cur_pos < s.len() {
let ch = s.as_bytes()[self.cur_pos] as char;
self.cur_pos += 1;
if ch.is_whitespace() {
break;
} else {
ret.push(ch);
}
}
}
ret
}
fn next_i32(&mut self) -> i32 {
let token = self.next_string();
token.parse::<i32>().unwrap()
}
fn next_f64(&mut self) -> f64 {
let token = self.next_string();
token.parse::<f64>().unwrap()
}
}
fn main() {
// this is a solution to https://www.hackerrank.com/challenges/sock-merchant/problem
let input = io::stdin();
// I want to read the inputs from file while I'm debugging
// When I submit it, I just need to comment out the next line
let input = File::open("in.txt").expect("");
let mut reader = BufReader::new(input);
let mut scan = Scan::new(&mut reader);
let N = scan.next_i32();
let mut socks = [0; 101];
let mut mps = HashMap::new();
for i in 0..N as usize {
socks[i] = scan.next_i32();
*mps.entry(socks[i]).or_insert(0) += 1;
}
let mut ans = 0;
for (k, v) in mps.iter() {
ans += v / 2;
}
println!("{}", ans);
}