From 5167f21bcaa574a4fa09d2052217ee5b3078f182 Mon Sep 17 00:00:00 2001 From: Lukas Kalbertodt Date: Wed, 4 Jan 2017 13:57:15 +0100 Subject: [PATCH] Add solution sheet7 --- aufgaben/sheet7/sol1/fib.rs | 31 +++++++++ aufgaben/sheet7/sol2/iters.rs | 93 +++++++++++++++++++++++++++ aufgaben/sheet7/sol3/fold.rs | 19 ++++++ aufgaben/sheet7/sol4/Cargo.lock | 4 ++ aufgaben/sheet7/sol4/Cargo.toml | 6 ++ aufgaben/sheet7/sol4/src/main.rs | 106 +++++++++++++++++++++++++++++++ 6 files changed, 259 insertions(+) create mode 100755 aufgaben/sheet7/sol1/fib.rs create mode 100755 aufgaben/sheet7/sol2/iters.rs create mode 100755 aufgaben/sheet7/sol3/fold.rs create mode 100755 aufgaben/sheet7/sol4/Cargo.lock create mode 100755 aufgaben/sheet7/sol4/Cargo.toml create mode 100755 aufgaben/sheet7/sol4/src/main.rs diff --git a/aufgaben/sheet7/sol1/fib.rs b/aufgaben/sheet7/sol1/fib.rs new file mode 100755 index 0000000..8d1a67d --- /dev/null +++ b/aufgaben/sheet7/sol1/fib.rs @@ -0,0 +1,31 @@ +struct Fib { + curr: u64, + last: u64, +} + +impl Fib { + fn new() -> Self { + Fib { + curr: 1, + last: 0, + } + } +} + +impl Iterator for Fib { + type Item = u64; + fn next(&mut self) -> Option { + let new = self.last + self.curr; + self.last = self.curr; + self.curr = new; + + Some(self.last) + } +} + + +fn main() { + for i in Fib::new().take(20) { + println!("{}", i); + } +} diff --git a/aufgaben/sheet7/sol2/iters.rs b/aufgaben/sheet7/sol2/iters.rs new file mode 100755 index 0000000..b13415d --- /dev/null +++ b/aufgaben/sheet7/sol2/iters.rs @@ -0,0 +1,93 @@ +fn factorial(x: u64) -> u64 { + (1..x + 1).product() +} + +#[test] +fn test_factorial() { + assert_eq!(factorial(1), 1); + assert_eq!(factorial(2), 2); + assert_eq!(factorial(3), 6); + assert_eq!(factorial(15), 1_307_674_368_000); +} + +fn is_palindrome(word: &str) -> bool { + word.chars() + .zip(word.chars().rev()) + // This is just an optional optimization + .take(word.len() / 2) + .all(|(a, b)| a == b) +} + +#[test] +fn test_is_palindrome() { + assert!(is_palindrome("bob")); + assert!(is_palindrome("anna")); + assert!(is_palindrome("lagerregal")); + + assert!(!is_palindrome("peter")); +} + +fn greatest_subsequencial_sum(arr: &[i64]) -> &[i64] { + // all possible window lengths + (1..arr.len() + 1) + // iterate over all possible windows + .flat_map(|len| arr.windows(len)) + // add the empty slice in case all numbers are negative + .chain(std::iter::once(&arr[0..0])) + // we want to select the window which sum is the greatest + .max_by_key(|win| win.iter().sum::()) + // we know our iterator has at least one element + .unwrap() +} + +#[test] +fn test_greatest_subsequencial_sum() { + let a = [1, 2, 39, 34, 20, -20, -16, 35, 0]; + assert_eq!(greatest_subsequencial_sum(&a), &a[0..5]); + + let b = [-3, -9, -8, -34]; + assert_eq!(greatest_subsequencial_sum(&b), &[]); +} + +fn rot13(s: &str) -> String { + s.chars().map(|c| { + match c { + 'a' ... 'm' | 'A' ... 'M' => (c as u8 + 13) as char, + 'n' ... 'z' | 'N' ... 'Z' => (c as u8 - 13) as char, + _ => c + } + }).collect() +} + +#[test] +fn test_rot13() { + assert_eq!(rot13("hello"), "uryyb"); + assert_eq!(rot13("uryyb"), "hello"); + + assert_eq!( + rot13("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"), + "NOPQRSTUVWXYZABCDEFGHIJKLMnopqrstuvwxyzabcdefghijklm" + ); + + assert_eq!(rot13("peter"), "crgre"); +} + +fn used_chars_count>(words: &[S]) -> usize { + use std::collections::HashSet; + + words.iter() + .flat_map(|w| w.as_ref().chars()) + .filter(|c| !c.is_whitespace()) + .collect::>() + .len() +} + +#[test] +fn test_used_letters() { + assert_eq!(used_chars_count(&["hi", "ih gitt"]), 4); + assert_eq!(used_chars_count(&["peter"]), 4); + assert_eq!(used_chars_count(&["p e t e r", "barbara"]), 6); +} + +fn main() { +} diff --git a/aufgaben/sheet7/sol3/fold.rs b/aufgaben/sheet7/sol3/fold.rs new file mode 100755 index 0000000..b534fc5 --- /dev/null +++ b/aufgaben/sheet7/sol3/fold.rs @@ -0,0 +1,19 @@ +fn main() { + // product + let fac_5 = (1..5).fold(1, |acc, x| acc * x); + assert_eq!(fac_5, (1..5).product()); + println!("5! = {}", fac_5); + + // max + let max = vec![3, 1, 4, 1, 5, 9, 2, 6] + .into_iter() + .fold(0, |acc, x| std::cmp::max(acc, x)); + assert_eq!(max, 9); + println!("max: {}", max); + + // all + let all_even = (1..9) + .fold(true, |acc, x| acc && (x % 2 == 0)); + assert!(!all_even); + println!("all_even: {}", all_even); +} diff --git a/aufgaben/sheet7/sol4/Cargo.lock b/aufgaben/sheet7/sol4/Cargo.lock new file mode 100755 index 0000000..5ed4ec3 --- /dev/null +++ b/aufgaben/sheet7/sol4/Cargo.lock @@ -0,0 +1,4 @@ +[root] +name = "mycp" +version = "0.1.0" + diff --git a/aufgaben/sheet7/sol4/Cargo.toml b/aufgaben/sheet7/sol4/Cargo.toml new file mode 100755 index 0000000..901cdde --- /dev/null +++ b/aufgaben/sheet7/sol4/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "mycp" +version = "0.1.0" +authors = ["Lukas Kalbertodt "] + +[dependencies] diff --git a/aufgaben/sheet7/sol4/src/main.rs b/aufgaben/sheet7/sol4/src/main.rs new file mode 100755 index 0000000..63ae389 --- /dev/null +++ b/aufgaben/sheet7/sol4/src/main.rs @@ -0,0 +1,106 @@ +use std::ffi::OsString; +use std::{fmt, io}; + +const USAGE: &'static str = " +Partial `cp` implementation in Rust. Copies files. + +Usage: + mycp +"; + +fn main() { + // First, try to parse the cmd args (we require exactly two args!) + let (from, to) = match parse_args() { + Err(e) => { + println!("{}", USAGE); + print_and_exit(e); + } + Ok(t) => t, + }; + + // Next, just copy from the first file to the second + if let Err(e) = copy(&from, &to) { + print_and_exit(e); + } +} + +/// Prints the given error, the USAGE string and exits with a non-zero exit +/// status. +fn print_and_exit(e: E) -> ! { + println!("error: {}", e); + std::process::exit(1); +} + +/// Tries to open file `from` for reading and file `to` for writing. Then +/// tries copy all contents from `from` to `to`. Returns first IO error. +fn copy(from: &str, to: &str) -> io::Result<()> { + use std::fs::File; + + let mut from = match File::open(from) { + Ok(f) => f, + Err(e) => return Err(e), + }; + let mut to = match File::create(to) { + Ok(f) => f, + Err(e) => return Err(e), + }; + + io::copy(&mut from, &mut to) + // we are not interested in the number of bytes written + .map(|_| ()) +} + +/// Tries to parse the command line args as two arguments. +fn parse_args() -> Result<(String, String), ArgsError> { + use std::env; + + match env::args_os().count() { + n if n > 4 => return Err(ArgsError::TooManyArgs(n - 1)), + n if n < 3 => return Err(ArgsError::NotEnoughArgs), + _ => {} + } + + env::args_os() + // only interested in the first two "real" arguments + .skip(1) + .take(2) + // try to convert each OsString into a proper Utf8 String + .map(|oss| oss.into_string()) + // collect to get the Result on the outside + .collect::, _>>() + // convert vector into tuple of Strings + .map(|mut v| (v.remove(0), v.remove(0))) + // wrap conversion error into our error type + .map_err(|oss| ArgsError::NotUtf8(oss)) +} + +/// Stuff that can go wrong while parsing command line args. +enum ArgsError { + NotEnoughArgs, + TooManyArgs(usize), + NotUtf8(OsString), +} + +impl fmt::Display for ArgsError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + ArgsError::NotEnoughArgs => { + write!(f, "not enough arguments given") + } + ArgsError::TooManyArgs(count) => { + write!( + f, + "too many arguments were given (expected 2, found {})", + count + ) + } + ArgsError::NotUtf8(ref oss) => { + write!( + f, + "given argument '{}' is not valid UTF8", + oss.to_string_lossy() + ) + } + } + } +}