Add solution sheet7

This commit is contained in:
Lukas Kalbertodt 2017-01-04 13:57:15 +01:00
parent 9f2347a0be
commit 5167f21bca
6 changed files with 259 additions and 0 deletions

31
aufgaben/sheet7/sol1/fib.rs Executable file
View File

@ -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<Self::Item> {
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);
}
}

93
aufgaben/sheet7/sol2/iters.rs Executable file
View File

@ -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::<i64>())
// 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<S: AsRef<str>>(words: &[S]) -> usize {
use std::collections::HashSet;
words.iter()
.flat_map(|w| w.as_ref().chars())
.filter(|c| !c.is_whitespace())
.collect::<HashSet<_>>()
.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() {
}

19
aufgaben/sheet7/sol3/fold.rs Executable file
View File

@ -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);
}

4
aufgaben/sheet7/sol4/Cargo.lock generated Executable file
View File

@ -0,0 +1,4 @@
[root]
name = "mycp"
version = "0.1.0"

View File

@ -0,0 +1,6 @@
[package]
name = "mycp"
version = "0.1.0"
authors = ["Lukas Kalbertodt <lukas.kalbertodt@gmail.com>"]
[dependencies]

106
aufgaben/sheet7/sol4/src/main.rs Executable file
View File

@ -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 <source> <destination>
";
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: fmt::Display>(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::<Result<Vec<_>, _>>()
// 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()
)
}
}
}
}