made some minor fixes
This commit is contained in:
+120
-39
@@ -1,7 +1,8 @@
|
|||||||
|
|
||||||
// Write some functions to:
|
// Write some functions to:
|
||||||
// 1. tokenize a string
|
// 1. tokenize a string
|
||||||
// 2. manually make a map of tokens:their_counts
|
// 2. manually make a map of tokens:their_counts (the purpose of this exercise was to exercise
|
||||||
|
// understanding of vectors/arrays and their slices, not to use hashmap)
|
||||||
// 3. analyze the token structure:
|
// 3. analyze the token structure:
|
||||||
// 3.a. count the words
|
// 3.a. count the words
|
||||||
// 3.b. count the unique words
|
// 3.b. count the unique words
|
||||||
@@ -9,18 +10,21 @@
|
|||||||
// 3.d. count the average word length
|
// 3.d. count the average word length
|
||||||
// 4. (pretty) print the info
|
// 4. (pretty) print the info
|
||||||
|
|
||||||
const PUNC: &str = ",.?:;'~|!@#$%^&*\"";
|
|
||||||
|
|
||||||
|
|
||||||
// todo: what about CTRL chars?
|
// todo: what about CTRL chars?
|
||||||
// todo: what about feeding Bytes?
|
// todo: what about feeding Bytes?
|
||||||
// todo: return Result for whitespace input
|
// todo: return Result for whitespace input
|
||||||
fn tokenize(input: &str) -> Vec<String> {
|
pub fn tokenize(input: &str) -> Vec<String> {
|
||||||
// filter punctuation
|
// filter punctuation
|
||||||
let mut s = String::new();
|
let mut s = String::new();
|
||||||
for c in input.chars() {
|
for c in input.chars() {
|
||||||
if !PUNC.contains(c) {
|
if !c.is_ascii_punctuation() {
|
||||||
s.push(c.to_lowercase().next().unwrap());
|
// to_lowercase on a char will always yield at least one char
|
||||||
|
// if a char lowercases to two chars then we don't truncate by using
|
||||||
|
// a for loop
|
||||||
|
for lc in c.to_lowercase() {
|
||||||
|
s.push(lc);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -29,29 +33,36 @@ fn tokenize(input: &str) -> Vec<String> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// todo: can the input type be better?
|
// todo: can the input type be better?
|
||||||
fn count_words(input: &[String]) -> Vec<(String,usize)> {
|
// total runtime complexity worst-case O(n log n)
|
||||||
|
pub fn create_frequency_vec(input: &[String]) -> Vec<(String,usize)> {
|
||||||
|
let mut sorted = input.to_vec();
|
||||||
|
sorted.sort(); // O(n log n)
|
||||||
|
|
||||||
let mut counts : Vec<(String, usize)> = Vec::new();
|
let mut counts : Vec<(String, usize)> = Vec::new();
|
||||||
for w in input {
|
for w in sorted { // O(n)
|
||||||
match counts.iter_mut().find(|(c,_)| c == w) {
|
match counts.last_mut() {
|
||||||
Some((_, count)) => *count += 1,
|
Some((last, count)) if last == &w => *count += 1,
|
||||||
_ => counts.push((w.to_string(), 1)),
|
_ => counts.push((w.to_string(), 1)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
counts.sort_by(|a,b| b.1.cmp(&a.1));
|
counts.sort_by(|a,b| b.1.cmp(&a.1)); // sort by frequency, O(m log m)
|
||||||
counts
|
counts
|
||||||
}
|
}
|
||||||
|
|
||||||
fn analyze_word_count(input: &[(String,usize)]) -> usize {
|
pub fn analyze_word_count(input: &[(String,usize)]) -> usize {
|
||||||
let mut count = 0;
|
let mut count = 0;
|
||||||
input.iter().for_each(|(_,c)| { count+=c });
|
input.iter().for_each(|(_,c)| { count+=c });
|
||||||
count
|
count
|
||||||
}
|
}
|
||||||
|
|
||||||
fn analyze_unique_word_count(input: &[(String,usize)]) -> usize {
|
pub fn analyze_unique_word_count(input: &[(String,usize)]) -> usize {
|
||||||
input.len()
|
input.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn average_word_length(input: &[(String, usize)]) -> usize {
|
pub fn average_word_length(input: &[(String, usize)]) -> f64 {
|
||||||
|
if input.is_empty() {
|
||||||
|
return 0 as f64;
|
||||||
|
}
|
||||||
let mut len = 0;
|
let mut len = 0;
|
||||||
let mut tokens = 0;
|
let mut tokens = 0;
|
||||||
input.iter().for_each(|(s,c)| {
|
input.iter().for_each(|(s,c)| {
|
||||||
@@ -59,43 +70,113 @@ fn average_word_length(input: &[(String, usize)]) -> usize {
|
|||||||
tokens += c;
|
tokens += c;
|
||||||
});
|
});
|
||||||
|
|
||||||
len/tokens
|
len as f64 /(tokens as f64)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn top_n_most_used(input: &[(String, usize)], n: usize) -> &[(String, usize)] {
|
pub fn top_n_most_used(input: &[(String, usize)], n: usize) -> &[(String, usize)] {
|
||||||
let n = n.min(input.len());
|
let n = n.min(input.len());
|
||||||
&input[..n]
|
&input[..n]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print(input: &[(String, usize)]) {
|
// todo: option
|
||||||
|
pub fn longest_word(input: &[(String, usize)]) -> usize {
|
||||||
|
let mut max = 0;
|
||||||
|
input.iter().for_each(|(w,_)| if w.len() > max { max = w.len() });
|
||||||
|
max
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn num_digits(n: usize) -> usize {
|
||||||
|
let mut n = n;
|
||||||
|
let mut count = 0;
|
||||||
|
while n > 0 {
|
||||||
|
count += 1;
|
||||||
|
n /= 10;
|
||||||
|
}
|
||||||
|
count
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn print_analysis(input: &[(String, usize)]) {
|
||||||
|
if input.is_empty() {
|
||||||
|
println!("No words to analyze");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let counts = input;
|
let counts = input;
|
||||||
let wc = analyze_word_count(&counts);
|
let wc = analyze_word_count(&counts);
|
||||||
|
let largest_freq = top_n_most_used(&counts, 1)[0].1;
|
||||||
|
let digits = num_digits(largest_freq);
|
||||||
|
|
||||||
// todo: clean this up a bit
|
let col1 = longest_word(&counts).max(5);
|
||||||
println!("Word Count % of total");
|
let col2 = digits.max(5);
|
||||||
println!("---------------------");
|
let col3 = 5;
|
||||||
|
let end = col1 + col2 + col3.max(11) + 2;
|
||||||
|
println!("{:<col1$} {:<col2$} {:<col3$}", "Word", "Count", "%_of_total");
|
||||||
|
println!("{:-<end$}", "");
|
||||||
for (w, c) in counts {
|
for (w, c) in counts {
|
||||||
println!("{} {} {}", w, c, *c as f64/(wc as f64));
|
println!("{:<col1$} {:<col2$} {:<col3$.2}%", w, c, (*c as f64/(wc as f64) * 100 as f64));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let tokens = tokenize("Hello, world! hello");
|
println!("playing around with vecs and slices");
|
||||||
assert_eq!(tokens.len(), 3);
|
println!("use `cargo test`");
|
||||||
|
println!("");
|
||||||
let counts = count_words(&tokens);
|
test_print();
|
||||||
let wc = analyze_word_count(&counts);
|
}
|
||||||
assert_eq!(wc, 3);
|
|
||||||
|
pub fn test_print() {
|
||||||
let uwc = analyze_unique_word_count(&counts);
|
let tokens = tokenize("Hellow, wod! hello hello hello ok bye then oa more plz");
|
||||||
assert_eq!(uwc, 2);
|
let freq_vec = create_frequency_vec(&tokens);
|
||||||
|
print_analysis(&freq_vec);
|
||||||
let avg_len = average_word_length(&counts);
|
}
|
||||||
assert_eq!(avg_len, 5);
|
|
||||||
|
#[cfg(test)]
|
||||||
let top_n = top_n_most_used(&counts, 4);
|
pub mod test {
|
||||||
assert_eq!(top_n[0].0, "hello");
|
use super::*;
|
||||||
|
|
||||||
print(&counts);
|
#[test]
|
||||||
|
pub fn empty_tests() {
|
||||||
|
let tokens = tokenize("");
|
||||||
|
assert_eq!(tokens.len(), 0);
|
||||||
|
|
||||||
|
let freq_vec = create_frequency_vec(&tokens);
|
||||||
|
assert_eq!(freq_vec.len(), 0);
|
||||||
|
|
||||||
|
let wc = analyze_word_count(&freq_vec);
|
||||||
|
assert_eq!(wc, 0);
|
||||||
|
|
||||||
|
let uwc = analyze_unique_word_count(&freq_vec);
|
||||||
|
assert_eq!(uwc, 0);
|
||||||
|
|
||||||
|
let avg_len = average_word_length(&freq_vec);
|
||||||
|
assert_eq!(avg_len, 0 as f64);
|
||||||
|
|
||||||
|
let top_n = top_n_most_used(&freq_vec, 4);
|
||||||
|
assert_eq!(top_n.len(), 0);
|
||||||
|
|
||||||
|
print_analysis(&freq_vec);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
pub fn basic_tests() {
|
||||||
|
let tokens = tokenize("Hello, world! hello");
|
||||||
|
assert_eq!(tokens.len(), 3);
|
||||||
|
|
||||||
|
let freq_vec = create_frequency_vec(&tokens);
|
||||||
|
assert_eq!(freq_vec.len(), 2);
|
||||||
|
|
||||||
|
let wc = analyze_word_count(&freq_vec);
|
||||||
|
assert_eq!(wc, 3);
|
||||||
|
|
||||||
|
let uwc = analyze_unique_word_count(&freq_vec);
|
||||||
|
assert_eq!(uwc, 2);
|
||||||
|
|
||||||
|
let avg_len = average_word_length(&freq_vec);
|
||||||
|
assert_eq!(avg_len, 5 as f64);
|
||||||
|
|
||||||
|
let top_n = top_n_most_used(&freq_vec, 4);
|
||||||
|
assert_eq!(top_n[0].0, "hello");
|
||||||
|
|
||||||
|
print_analysis(&freq_vec);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user