mirror of
https://github.com/LukasKalbertodt/programmieren-in-rust.git
synced 2024-11-18 02:48:58 +01:00
Add solution sheet7
This commit is contained in:
parent
9f2347a0be
commit
5167f21bca
31
aufgaben/sheet7/sol1/fib.rs
Executable file
31
aufgaben/sheet7/sol1/fib.rs
Executable 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
93
aufgaben/sheet7/sol2/iters.rs
Executable 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
19
aufgaben/sheet7/sol3/fold.rs
Executable 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
4
aufgaben/sheet7/sol4/Cargo.lock
generated
Executable file
@ -0,0 +1,4 @@
|
||||
[root]
|
||||
name = "mycp"
|
||||
version = "0.1.0"
|
||||
|
6
aufgaben/sheet7/sol4/Cargo.toml
Executable file
6
aufgaben/sheet7/sol4/Cargo.toml
Executable 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
106
aufgaben/sheet7/sol4/src/main.rs
Executable 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()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user