Skip to content

Commit

Permalink
Use Rayon's reduce and im's union_with
Browse files Browse the repository at this point in the history
This creates a new HashMap in each `tally_words` call. We can thus omit
using a Mutex. Instead of doing `for_each` with side effects, we use
`reduce` (Rayon's parallel version of it) to build the final map of
words.

The reason I used the im crate is because it has a very nice
`union_with` method on its HashMap; you can also replace `im::HashMap`
with `im::OrdMap` if you want to get sorted output directly.

I have no idea if this is faster, but it does show a different way of
using concurrency.
  • Loading branch information
killercup committed Sep 2, 2018
1 parent d495abe commit 152163e
Showing 1 changed file with 24 additions and 21 deletions.
45 changes: 24 additions & 21 deletions episode/9/rust/pascal/src/main.rs
@@ -1,35 +1,39 @@
extern crate rayon;
#[macro_use] extern crate structopt;
#[macro_use]
extern crate structopt;
extern crate im;

use im::HashMap;
use rayon::prelude::*;
use structopt::StructOpt;
use im::ordmap::OrdMap;
use std::error::Error;
use std::fs;
use std::path::{PathBuf, Path};
use std::path::{Path, PathBuf};
use structopt::StructOpt;

#[derive(StructOpt)]
struct Cli {
#[structopt(name = "FILE", parse(from_os_str))]
files: Vec<PathBuf>,
}

#[derive(Debug)]
enum Error {
Lock,
}

type Words = OrdMap<String, u32>;
type Words = HashMap<String, u32>;

fn main() -> Result<(), Box<Error>> {
let mut words = Words::new();
let args = Cli::from_args();

args.files
let words = args
.files
.par_iter()
.for_each(|filename| tally_words(filename, &mut words).unwrap());

for (word, count) in words.iter() {
.map(|filename| {
tally_words(filename)
.map_err(|e| eprintln!("Error processing {}: {:?}", filename.display(), e))
.unwrap_or_default()
}).reduce(
|| Words::new(),
|result, current| current.union_with(result, |a, b| a + b),
);

for (word, count) in &words {
if *count > 1 {
println!("{} {}", count, word)
}
Expand All @@ -38,14 +42,13 @@ fn main() -> Result<(), Box<Error>> {
Ok(())
}

fn tally_words(filename: &Path, words: &mut Words) -> Result<(), Box<Error>> {
let contents = fs::read_to_string(filename).expect("Unable to read file");
fn tally_words(filename: &Path) -> Result<Words, Box<Error>> {
let mut words = Words::new();
let contents = fs::read_to_string(filename)?;

for s in contents.split_whitespace() {
let key = s.to_lowercase();
{
*words.entry(key).or_insert(0) += 1;
}
*words.entry(key).or_insert(0) += 1;
}
Ok(())
Ok(words)
}

0 comments on commit 152163e

Please sign in to comment.