Initial commit
This commit is contained in:
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Gradle build configuration for specific lab module / exercise
|
||||
*/
|
||||
// enabled plugins
|
||||
plugins {
|
||||
id 'java'
|
||||
}
|
||||
|
||||
// Project/Module information
|
||||
description = 'Lab06 Stepik Solution'
|
||||
group = 'ch.zhaw.prog2'
|
||||
version = '2022.1'
|
||||
|
||||
// Dependency configuration
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
// Junit 5 dependencies
|
||||
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.+'
|
||||
testImplementation 'org.junit.jupiter:junit-jupiter-params:5.8.+'
|
||||
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.+'
|
||||
// Mockito dependencies
|
||||
testImplementation 'org.mockito:mockito-core:4.3.+'
|
||||
}
|
||||
|
||||
// Test task configuration
|
||||
test {
|
||||
// Use JUnit platform for unit tests
|
||||
useJUnitPlatform()
|
||||
// Output results of individual tests
|
||||
testLogging {
|
||||
events "PASSED", "SKIPPED", "FAILED"
|
||||
}
|
||||
}
|
||||
|
||||
// Java plugin configuration
|
||||
java {
|
||||
// By default the Java version of the gradle process is used as source/target version.
|
||||
// This can be overridden, to ensure a specific version. Enable only if required.
|
||||
sourceCompatibility = JavaVersion.VERSION_17 // ensure Java source code compatibility
|
||||
targetCompatibility = JavaVersion.VERSION_17 // version of the created byte-code
|
||||
|
||||
// Java compiler specific options
|
||||
compileJava {
|
||||
// source files should be UTF-8 encoded
|
||||
options.encoding = 'UTF-8'
|
||||
// for more options see https://docs.gradle.org/current/dsl/org.gradle.api.tasks.compile.CompileOptions.html
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
package ch.zhaw.prog2.functional;
|
||||
|
||||
import java.security.MessageDigest;
|
||||
import java.util.Base64;
|
||||
import java.util.Scanner;
|
||||
|
||||
/**
|
||||
* Class taken from <a href="https://stepik.org/lesson/46943/step/2?unit=24990">Stepik exercise</a>
|
||||
*/
|
||||
class ChainOfResponsibilityDemo {
|
||||
|
||||
/**
|
||||
* Accepts a request and returns new request with data wrapped in the tag <transaction>...</transaction>
|
||||
*/
|
||||
static RequestHandler wrapInTransactionTag = req ->
|
||||
new Request(String.format("<transaction>%s</transaction>", req.getData()));
|
||||
|
||||
/**
|
||||
* Accepts a request and returns a new request with calculated digest inside the tag <digest>...</digest>
|
||||
*/
|
||||
static RequestHandler createDigest = req -> {
|
||||
String digest = "";
|
||||
try {
|
||||
final MessageDigest md5 = MessageDigest.getInstance("MD5");
|
||||
final byte[] digestBytes = md5.digest(req.getData().getBytes("UTF-8"));
|
||||
digest = new String(Base64.getEncoder().encode(digestBytes));
|
||||
} catch (Exception ignored) {
|
||||
System.out.println("An error occurred");
|
||||
}
|
||||
return new Request(req.getData() + String.format("<digest>%s</digest>", digest));
|
||||
};
|
||||
|
||||
/**
|
||||
* Accepts a request and returns a new request with data wrapped in the tag <request>...</request>
|
||||
*/
|
||||
static RequestHandler wrapInRequestTag = req ->
|
||||
new Request(String.format("<request>%s</request>", req.getData()));
|
||||
|
||||
/**
|
||||
* It should represents a chain of responsibility combined from another handlers.
|
||||
* The format: commonRequestHandler = handler1.setSuccessor(handler2.setSuccessor(...))
|
||||
* The combining method setSuccessor may has another name
|
||||
*/
|
||||
static RequestHandler commonRequestHandler = // !!! write a combination of existing handlers here
|
||||
wrapInRequestTag.wrapFirst(createDigest.wrapFirst(wrapInTransactionTag));
|
||||
|
||||
/**
|
||||
* It represents a handler and has two methods: one for handling requests and other for combining handlers
|
||||
*/
|
||||
@FunctionalInterface
|
||||
interface RequestHandler {
|
||||
|
||||
// !!! write a method handle that accept request and returns new request here
|
||||
// it allows to use lambda expressions for creating handlers below
|
||||
Request handle(Request request);
|
||||
|
||||
// !!! write a default method for combining this and other handler single one
|
||||
// the order of execution may be any but you need to consider it when composing handlers
|
||||
// the method may has any name
|
||||
default RequestHandler wrapFirst(RequestHandler otherHandler) {
|
||||
return request -> handle(otherHandler.handle(request));
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Immutable class for representing requests.
|
||||
* If you need to change the request data then create new request.
|
||||
*/
|
||||
static class Request {
|
||||
private final String data;
|
||||
|
||||
public Request(String requestData) {
|
||||
this.data = requestData;
|
||||
}
|
||||
|
||||
public String getData() {
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
// Don't change the code below
|
||||
public static void main(String[] args) throws Exception {
|
||||
final Scanner scanner = new Scanner(System.in);
|
||||
final String requestData = scanner.nextLine();
|
||||
final Request notCompletedRequest = new Request(requestData);
|
||||
System.out.println(commonRequestHandler.handle(notCompletedRequest).getData());
|
||||
}
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
package ch.zhaw.prog2.functional.stepik;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.IntPredicate;
|
||||
|
||||
public class ComposingPredicate {
|
||||
|
||||
/**
|
||||
* The method represents a disjunct operator for a list of predicates.
|
||||
* For an empty list it returns the always false predicate.
|
||||
*/
|
||||
public static IntPredicate disjunctAll(List<IntPredicate> predicates) {
|
||||
return predicates.stream().reduce(x -> false, (a, b) -> a.or(b));
|
||||
}
|
||||
|
||||
/**
|
||||
* Using anyMatch to reduce compute time if possible
|
||||
*/
|
||||
public static IntPredicate disjunctAllFaster(List<IntPredicate> predicates) {
|
||||
return i -> predicates.stream().anyMatch(p -> p.test(i));
|
||||
}
|
||||
|
||||
/**
|
||||
* Classical implementation provided by lecturer to help you solve this exercise.
|
||||
* <p>
|
||||
* This solution works, but you have to search a solution using streams which will lead you
|
||||
* to a solution with less lines of code.
|
||||
*/
|
||||
public static IntPredicate disjunctAllNoStream(List<IntPredicate> predicates) {
|
||||
IntPredicate disjunct = x -> false;
|
||||
for (IntPredicate currentPredicate : predicates) {
|
||||
disjunct = disjunct.or(currentPredicate);
|
||||
}
|
||||
return disjunct;
|
||||
}
|
||||
}
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
package ch.zhaw.prog2.functional.stepik;
|
||||
|
||||
import ch.zhaw.prog2.functional.stepik.ComposingPredicate;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.IntPredicate;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
/**
|
||||
* Do not modify this test class
|
||||
*/
|
||||
class ComposingPredicateTest {
|
||||
private static final IntPredicate isEven = x -> x % 2 == 0;
|
||||
private static final IntPredicate isDividableBy3 = x -> x % 3 == 0;
|
||||
private static final List<IntPredicate> predicateList = List.of(isEven, isDividableBy3);
|
||||
private List<Integer> expected;
|
||||
private IntStream testIntegers;
|
||||
|
||||
/*
|
||||
* This tests your solution
|
||||
*/
|
||||
@Test
|
||||
void disjunctAll() {
|
||||
assertDoesNotThrow(
|
||||
() -> ComposingPredicate.disjunctAll(List.of(x -> true)),
|
||||
"You have to implement ComposingPredicate.disjunctAll"
|
||||
);
|
||||
IntPredicate alwaysTrue = ComposingPredicate.disjunctAll(List.of(x -> true));
|
||||
assertTrue(alwaysTrue.test(1), "Test with one predicate only");
|
||||
|
||||
IntPredicate dividableBy2Or3 = ComposingPredicate.disjunctAll(predicateList);
|
||||
assertArrayEquals(expected.toArray(), testIntegers.filter(dividableBy2Or3).boxed().toArray());
|
||||
}
|
||||
|
||||
/*
|
||||
* This tests the alternative solution which tries to reduce compute time
|
||||
*/
|
||||
@Test
|
||||
void disjunctAllFaster() {
|
||||
IntPredicate alwaysTrue = ComposingPredicate.disjunctAllFaster(List.of(x -> true));
|
||||
assertTrue(alwaysTrue.test(1), "Test with one predicate only");
|
||||
|
||||
IntPredicate dividableBy2Or3 = ComposingPredicate.disjunctAllFaster(predicateList);
|
||||
assertArrayEquals(expected.toArray(), testIntegers.filter(dividableBy2Or3).boxed().toArray());
|
||||
}
|
||||
|
||||
/*
|
||||
* This tests the given classical solution without streams
|
||||
*/
|
||||
@Test
|
||||
void disjunctAllNoStream() {
|
||||
IntPredicate alwaysTrue = ComposingPredicate.disjunctAllNoStream(List.of(x -> true));
|
||||
assertTrue(alwaysTrue.test(1), "Test with one predicate only");
|
||||
|
||||
IntPredicate dividableBy2Or3 = ComposingPredicate.disjunctAllNoStream(predicateList);
|
||||
assertArrayEquals(expected.toArray(), testIntegers.filter(dividableBy2Or3).boxed().toArray());
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
testIntegers = IntStream.range(1, 10);
|
||||
expected = List.of(2, 3, 4, 6, 8, 9);
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 121 KiB |
@@ -0,0 +1,239 @@
|
||||
:source-highlighter: coderay
|
||||
:icons: font
|
||||
:experimental:
|
||||
:!sectnums:
|
||||
:imagesdir: ./images/
|
||||
:codedir: ./code/
|
||||
:logo: IT.PROG2 -
|
||||
ifdef::backend-html5[]
|
||||
:logo: image:PROG2-300x300.png[IT.PROG2,100,100,role=right,fit=none,position=top right]
|
||||
endif::[]
|
||||
ifdef::backend-pdf[]
|
||||
:logo:
|
||||
endif::[]
|
||||
ifdef::env-github[]
|
||||
:tip-caption: :bulb:
|
||||
:note-caption: :information_source:
|
||||
:important-caption: :heavy_exclamation_mark:
|
||||
:caution-caption: :fire:
|
||||
:warning-caption: :warning:
|
||||
endif::[]
|
||||
|
||||
= {logo} Lösungen zu den Übungsaufgaben Functional Programming
|
||||
|
||||
:sectnums:
|
||||
:sectnumlevels: 1
|
||||
// Beginn des Aufgabenblocks
|
||||
|
||||
== Functional Interfaces [TU]
|
||||
|
||||
[loweralpha]
|
||||
. Welche Interfaces aus dem Package `java.util.function` können Sie alles nutzen, um
|
||||
- die mathematische Funktion f(x) = x ^ 2 - 3 für Zahlen des Typs `long` abzubilden?
|
||||
[numbered]
|
||||
.. `LongUnaryOperator`
|
||||
.. `LongFunction<R>` als `LongFunction<Long>`
|
||||
.. `ToLongFunction<T>` als `ToLongFunction<Long>`
|
||||
.. `UnaryOperator<T>` als `UnaryOperator<Long>`
|
||||
.. `Function<T,R>` als `Function<Long,Long>`
|
||||
|
||||
- um den Zinsfaktor (double) für n (int) Jahre bei einem Zinssatz von p Prozent (float) zu berechnen mit der Formel
|
||||
zf = (1 + p / 100)^n ?
|
||||
[numbered]
|
||||
.. `ToDoubleBiFunction<T,U>` als `ToDoubleBiFunction<Integer,Float>`
|
||||
.. `BiFunction<T,U,R>` als `BiFunction<Integer,Float,Double>`
|
||||
|
||||
- ein Objekt vom Typ `Person` (ohne Parameter) zu generieren?
|
||||
[numbered]
|
||||
.. `Supplier<T>` als `Supplier<Person>`
|
||||
|
||||
. Welche Eigenschaft muss eine Funktion haben, damit Sie ein eigenes Interface schreiben müssen,
|
||||
also keines der in `java.util.function` vorhandenen Interfaces verwenden können?
|
||||
[numbered]
|
||||
.. Sie muss mehr als zwei Parameter haben
|
||||
|
||||
. Welche der Aussagen stimmen für ein funktionales Interface?
|
||||
** [x] Es ist ein Java-Interface (Schlüsselwort `interface` im Code)
|
||||
** [x] Es hat **genau eine** abstrakte Methode
|
||||
** [ ] Das Interface **muss** mit `@FunctionalInterface` markiert sein
|
||||
** [ ] Es hat **keine** default-Methoden (Schlüsselwort `default`)
|
||||
. Welche Aussagen stimmen?
|
||||
** [x] Zu **jedem** funktionalen Interface können Lambda-Ausdrücke (_lambda expressions_) geschrieben werden
|
||||
** [ ] Ein Lambda-Ausdruck kann **ohne** passendes funktionales Interface erstellt werden
|
||||
** [ ] Eine Variable vom Typ `Optional` kann nie `null` sein.
|
||||
|
||||
== Übungen auf der Stepik-Plattform [PU]
|
||||
|
||||
=== Übungen zu Functional Interface und Lambda Expression
|
||||
[loweralpha]
|
||||
. Identify the correct lambdas and method references
|
||||
+
|
||||
Korrekt sind:
|
||||
|
||||
* `x -> { }`
|
||||
* `() -> 3`
|
||||
|
||||
. Writing simple lambda expressions
|
||||
+
|
||||
[source]
|
||||
----
|
||||
(x, y) -> (x > y?x:y);
|
||||
----
|
||||
|
||||
. Too many arguments
|
||||
+
|
||||
`String.join()` dürfte effizienter sein als das Zusammenfügen von Strings mit `+`.
|
||||
+
|
||||
[source]
|
||||
----
|
||||
(a, b, c, d, e, f, g) -> String.join("", a, b, c, d, e, f, g).toUpperCase();
|
||||
----
|
||||
|
||||
. Writing closures
|
||||
+
|
||||
[source]
|
||||
----
|
||||
x -> a*x*x + b*x+c;
|
||||
----
|
||||
|
||||
. Replacing anonymous classes with lambda expressions
|
||||
Alles korrekt, ausser `Iterator<Integer> iterator = new Iterator<Integer>() ...`
|
||||
|
||||
. Matching the functional interfaces
|
||||
+
|
||||
[%header]
|
||||
|===
|
||||
|function | lambda expression
|
||||
|IntSupplier | `() \-> 3`
|
||||
|Consumer<String> | `System.out::println`
|
||||
|BiPredicate<Integer,Integer>|`(x,y) \-> x % y == 0`
|
||||
|DoubleUnaryOperator|`Math::sin`
|
||||
|Function<Double,String>|`(x) \-> String.valueOf(x*x)`
|
||||
|===
|
||||
+
|
||||
|
||||
. Your own functional interface
|
||||
+
|
||||
[source, Java]
|
||||
----
|
||||
class Solution {
|
||||
@FunctionalInterface
|
||||
public interface TernaryIntPredicate {
|
||||
boolean test(int a, int b, int c);
|
||||
}
|
||||
public static final TernaryIntPredicate allValuesAreDifferentPredicate =
|
||||
(x, y, z) -> (x != y && y != z && z != x);
|
||||
}
|
||||
----
|
||||
|
||||
=== Übungen mit Streams
|
||||
[loweralpha, start=8]
|
||||
. Calculating production of all numbers in the range
|
||||
+
|
||||
[source]
|
||||
----
|
||||
(l,r) -> LongStream.rangeClosed(l,r).reduce(1, (x,y) -> x*y);
|
||||
----
|
||||
|
||||
. Getting distinct strings
|
||||
+
|
||||
[source]
|
||||
----
|
||||
list -> list.stream().distinct().collect(Collectors.toList());
|
||||
----
|
||||
|
||||
. Composing predicates
|
||||
+
|
||||
[source, Java]
|
||||
----
|
||||
class Solution {
|
||||
public static IntPredicate disjunctAll(List<IntPredicate> predicates) {
|
||||
return predicates.stream().reduce(x -> false, (a, b) -> a.or(b));
|
||||
}
|
||||
}
|
||||
----
|
||||
Sie können auch den zweiten Parameter in Reduce durch `IntPredicate::or` ersetzen.
|
||||
+
|
||||
Oder mit meistens weniger Rechenaufwand:
|
||||
+
|
||||
[source, Java]
|
||||
----
|
||||
class Solution {
|
||||
public static IntPredicate disjunctAllAnyMatch(List<IntPredicate> predicates) {
|
||||
return i -> predicates.stream().anyMatch(p -> p.test(i));
|
||||
}
|
||||
}
|
||||
----
|
||||
. Lösen Sie die folgenden Aufgaben mit Streams:
|
||||
** Numbers filtering
|
||||
+
|
||||
[source, Java]
|
||||
----
|
||||
class Solution {
|
||||
public static IntStream createFilteringStream(IntStream evenStream, IntStream oddStream) {
|
||||
IntStream res = IntStream.concat(evenStream, oddStream);
|
||||
return res.filter(n -> n % 15 == 0).sorted().skip(2);
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
** Calculating a factorial
|
||||
+
|
||||
[source, Java]
|
||||
----
|
||||
class Solution {
|
||||
public static long factorial(long n) {
|
||||
return LongStream.rangeClosed(1L,n).reduce(1L, (a,b) -> a*b);
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
** The sum of odd numbers
|
||||
+
|
||||
[source]
|
||||
----
|
||||
return LongStream.rangeClosed(start, end).filter(n -> n%2 == 1).sum();
|
||||
----
|
||||
|
||||
** Collectors in practice: the product of squares
|
||||
+
|
||||
[source]
|
||||
----
|
||||
Collectors.reducing(1, (a, b) -> a * b*b);
|
||||
----
|
||||
|
||||
** Almost like a SQL: the total sum of transactions by each account
|
||||
+
|
||||
[source]
|
||||
----
|
||||
Collectors.groupingBy(
|
||||
transaction -> transaction.getAccount().getNumber(),
|
||||
Collectors.summingLong(Transaction::getSum));
|
||||
----
|
||||
|
||||
|
||||
|
||||
== Design Pattern _Chain of responsibility_ [PU]
|
||||
|
||||
[source, Java]
|
||||
----
|
||||
class Solution {
|
||||
@FunctionalInterface
|
||||
interface RequestHandler {
|
||||
Request handle(Request request);
|
||||
default RequestHandler wrapFirst(RequestHandler otherHandler) {
|
||||
return request -> handle(otherHandler.handle(request));
|
||||
}
|
||||
}
|
||||
|
||||
final static RequestHandler commonRequestHandler =
|
||||
wrapInRequestTag.wrapFirst(createDigest.wrapFirst(wrapInTransactionTag));
|
||||
}
|
||||
----
|
||||
|
||||
|
||||
|
||||
== Company Payroll [PA]
|
||||
****
|
||||
Die Lösungen zu den bewerteten Pflichtaufgaben erhalten Sie nach der Abgabe und Bewertung aller Klassen.
|
||||
****
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user