Simon Exercise List
SubTask 1 Search for an element using lineal search.
SubTask 2 Search for an element using dichotomic search.
SubTask 3 Order a list using insertion sort.
SubTask 4 Order a list using selection sort.
SubTask 5 Random permutation of the elements of a list.
SubTask 6 Merge the elements, in order, of two ordered lists.
package Test;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;
/**
* A utility class providing common algorithms for working with lists.
* <p>
* All methods are {@code static} so the class is not intended to be instantiated.
* </p>
*/
public final class ListUtils {
// Private constructor to prevent instantiation
private ListUtils() {
throw new AssertionError("Cannot instantiate utility class");
}
/* ===============================================================
* SubTask 1 – Linear Search
* =============================================================== */
/**
* Searches the list linearly for the given {@code key}.
*
* Precondition:
* 1. {@code list} is not {@code null}.
*
* Postcondition:
* 1. Returns the index of the first occurrence of {@code key} if present; otherwise returns {@code -1}.
* 2. {@code list} remains unmodified.
*
* @param list the list to search
* @param key the element to find
* @param <T> the type of elements in the list
* @return the index of {@code key} in {@code list}, or {@code -1} if not found
*/
public static <T> int linearSearch(List<T> list, T key) {
if (list == null) {
throw new IllegalArgumentException("List must not be null");
}
for (int i = 0; i < list.size(); i++) {
if ((key == null && list.get(i) == null) || (key != null && key.equals(list.get(i)))) {
return i;
}
}
return -1;
}
/* ===============================================================
* SubTask 2 – Dichotomic (Binary) Search
* =============================================================== */
/**
* Searches the sorted list for the given {@code key} using the binary search algorithm.
*
* Precondition:
* 1. {@code list} is not {@code null} and is sorted in non-decreasing order.
*
* Postcondition:
* 1. Returns the index of {@code key} if present; otherwise returns {@code -1}.
* 2. {@code list} remains unmodified.
*
* @param list the <em>sorted</em> list to search
* @param key the element to find
* @param <T> the type of elements in the list; must be {@link Comparable}
* @return the index of {@code key} in {@code list}, or {@code -1} if not found
*/
public static <T extends Comparable<? super T>> int binarySearch(List<T> list, T key) {
if (list == null) {
throw new IllegalArgumentException("List must not be null");
}
int low = 0;
int high = list.size() - 1;
while (low <= high) {
int mid = low + (high - low) / 2;
T midVal = list.get(mid);
int cmp = (key == null)
? (midVal == null ? 0 : -1)
: (midVal == null ? 1 : key.compareTo(midVal));
if (cmp == 0) {
return mid;
} else if (cmp < 0) {
high = mid - 1;
} else {
low = mid + 1;
}
}
return -1;
}
/* ===============================================================
* SubTask 3 – Insertion Sort
* =============================================================== */
/**
* Sorts the given list in-place using the insertion sort algorithm.
*
* Precondition:
* 1. {@code list} is not {@code null}.
*
* Postcondition:
* 1. Upon completion, {@code list} is sorted in non-decreasing order.
*
* @param list the list to sort
* @param <T> the element type; must be {@link Comparable}
*/
public static <T extends Comparable<? super T>> void insertionSort(List<T> list) {
if (list == null) {
throw new IllegalArgumentException("List must not be null");
}
for (int i = 1; i < list.size(); i++) {
T key = list.get(i);
int j = i - 1;
// Shift larger elements to the right
while (j >= 0 && (list.get(j) != null && key != null && list.get(j).compareTo(key) > 0
|| list.get(j) != null && key == null)) {
list.set(j + 1, list.get(j));
j--;
}
list.set(j + 1, key);
}
}
/* ===============================================================
* SubTask 4 – Selection Sort
* =============================================================== */
/**
* Sorts the given list in-place using the selection sort algorithm.
*
* Precondition:
* 1. {@code list} is not {@code null}.
*
* Postcondition:
* 1. Upon completion, {@code list} is sorted in non-decreasing order.
*
* @param list the list to sort
* @param <T> the element type; must be {@link Comparable}
*/
public static <T extends Comparable<? super T>> void selectionSort(List<T> list) {
if (list == null) {
throw new IllegalArgumentException("List must not be null");
}
int n = list.size();
for (int i = 0; i < n - 1; i++) {
int minIndex = i;
for (int j = i + 1; j < n; j++) {
T current = list.get(j);
T min = list.get(minIndex);
if ((current != null && min == null) || (current != null && min != null && current.compareTo(min) < 0)) {
minIndex = j;
}
}
if (minIndex != i) {
Collections.swap(list, i, minIndex);
}
}
}
/* ===============================================================
* SubTask 5 – Random Permutation (Shuffle)
* =============================================================== */
/**
* Generates a random permutation of the elements of the given list (in-place).
*
* Precondition:
* 1. {@code list} is not {@code null}.
*
* Postcondition:
* 1. After execution, {@code list} contains the same elements in a random order.
*
* @param list the list to shuffle
* @param rnd the random source; if {@code null}, a new {@link Random} will be used
* @param <T> the element type
*/
public static <T> void shuffle(List<T> list, Random rnd) {
if (list == null) {
throw new IllegalArgumentException("List must not be null");
}
if (rnd == null) {
rnd = new Random();
}
// Fisher–Yates shuffle
for (int i = list.size() - 1; i > 0; i--) {
int j = rnd.nextInt(i + 1);
Collections.swap(list, i, j);
}
}
/* ===============================================================
* SubTask 6 – Merge Two Ordered Lists
* =============================================================== */
/**
* Merges two <em>sorted</em> lists into a new sorted list.
*
* Precondition:
* 1. {@code a} and {@code b} are not {@code null} and are both sorted in non-decreasing order.
*
* Postcondition:
* 1. Returns a new list containing all elements of {@code a} and {@code b} in sorted order.
* 2. The original lists {@code a} and {@code b} remain unmodified.
*
* @param a the first sorted list
* @param b the second sorted list
* @param <T> the element type; must be {@link Comparable}
* @return a new sorted list containing the merged elements
*/
public static <T extends Comparable<? super T>> List<T> merge(List<T> a, List<T> b) {
if (a == null || b == null) {
throw new IllegalArgumentException("Input lists must not be null");
}
List<T> result = new ArrayList<>(a.size() + b.size());
int i = 0, j = 0;
while (i < a.size() && j < b.size()) {
T elemA = a.get(i);
T elemB = b.get(j);
if ((elemA == null && elemB == null) || (elemA != null && elemB != null && elemA.compareTo(elemB) <= 0) || (elemA == null)) {
result.add(elemA);
i++;
} else {
result.add(elemB);
j++;
}
}
// Append remaining elements
while (i < a.size()) {
result.add(a.get(i++));
}
while (j < b.size()) {
result.add(b.get(j++));
}
return result;
}
}
Implement predicate
package functions;
/**
* A predicate that checks if an integer is positive (> 0).
* @version 0.1
*/
public class Predicate1 implements Predicate<Integer> {
@Override
public boolean canApply(Integer source) {
return source != null;
}
@Override
public Boolean apply(Integer source) {
assert source != null : "source cannot be null";
return source > 0;
}
@Override
public boolean equals(Object other) {
return other instanceof Predicate1;
}
@Override
public String toString() {
return "Predicate1: isPositive";
}
}
Arraylist object array
package collections;
import functions.Action;
import functions.BinaryFunction;
import functions.Function;
import functions.Predicate;
/**
* An array implementation of a list.
* @see {@link collections.List}
* @version 0.1
*/
public class ArrayList<T> extends AbstractList<T> {
/**
* Default initial capacity for the internal array.
*/
private static final int DEFAULT_CAPACITY = 10;
/**
* Backing array that stores the elements of this list. Only the
* first {@code size} positions are in use – positions beyond that
* index may contain stale values (or {@code null}).
*/
private Object[] elements;
/**
* Current number of elements stored in this list. Always
* non-negative and never greater than {@code elements.length}.
*/
private int size;
/**
* Builds an empty list with the default initial capacity.
*/
public ArrayList() {
this(DEFAULT_CAPACITY);
}
/**
* Builds an empty list with a specific initial capacity.
*
* @param initialCapacity the initial capacity for the backing array
* @throws IllegalArgumentException if {@code initialCapacity < 0}
*/
public ArrayList(int initialCapacity) {
if (initialCapacity < 0) {
throw new IllegalArgumentException("initialCapacity must be >= 0");
}
this.elements = new Object[initialCapacity];
this.size = 0;
}
/* =============================================================
* Helper methods
* ============================================================= */
/**
* Ensures that the backing array can hold at least
* {@code minCapacity} elements. If it cannot, a bigger array is
* allocated and the existing elements are copied over.
*/
private void ensureCapacity(int minCapacity) {
if (minCapacity <= elements.length) {
return;
}
int newCapacity = Math.max(elements.length * 2 + 1, minCapacity);
Object[] newArr = new Object[newCapacity];
System.arraycopy(elements, 0, newArr, 0, size);
elements = newArr;
}
/**
* Checks that an index is in the range {@code 0 ≤ index < size}.
*/
private void checkElementIndex(int index) {
if (index < 0 || index >= size) {
throw new IllegalArgumentException("index out of range");
}
}
/**
* Checks that an index is in the range {@code 0 ≤ index ≤ size}
* (note the inclusive upper bound – suitable for insertion).
*/
private void checkPositionIndex(int index) {
if (index < 0 || index > size) {
throw new IllegalArgumentException("index out of range");
}
}
@SuppressWarnings("unchecked")
@Override
public T get(int i) {
checkElementIndex(i);
return (T) elements[i];
}
@Override
public void add(T elem) {
add(elem, size); // append is just insert at the end
}
@Override
public void add(T elem, int i) {
checkPositionIndex(i);
ensureCapacity(size + 1);
// shift elements to the right
int numMoved = size - i;
if (numMoved > 0) {
System.arraycopy(elements, i, elements, i + 1, numMoved);
}
elements[i] = elem;
size++;
}
@Override
public void remove(T elem) {
for (int i = 0; i < size; i++) {
if (java.util.Objects.equals(elements[i], elem)) {
remove(i);
return;
}
}
}
@Override
public void remove(int i) {
checkElementIndex(i);
int numMoved = size - i - 1;
if (numMoved > 0) {
System.arraycopy(elements, i + 1, elements, i, numMoved);
}
elements[--size] = null; // clear to let GC do its work
}
@Override
public <E> List<E> map(Function<? super T, ? extends E> function) {
if (function == null) {
throw new IllegalArgumentException("null argument");
}
ArrayList<E> result = new ArrayList<>(size);
for (int i = 0; i < size; i++) {
@SuppressWarnings("unchecked")
T value = (T) elements[i];
result.add(function.apply(value));
}
return result;
}
@Override
public boolean all(Predicate<? super T> predicate) {
if (predicate == null) {
throw new IllegalArgumentException("null argument");
}
for (int i = 0; i < size; i++) {
@SuppressWarnings("unchecked")
T value = (T) elements[i];
if (!predicate.test(value)) {
return false;
}
}
return true;
}
@Override
public boolean any(Predicate<? super T> predicate) {
if (predicate == null) {
throw new IllegalArgumentException("null argument");
}
for (int i = 0; i < size; i++) {
@SuppressWarnings("unchecked")
T value = (T) elements[i];
if (predicate.test(value)) {
return true;
}
}
return false;
}
@Override
public List<T> filter(Predicate<? super T> predicate) {
if (predicate == null) {
throw new IllegalArgumentException("null argument");
}
ArrayList<T> result = new ArrayList<>();
for (int i = 0; i < size; i++) {
@SuppressWarnings("unchecked")
T value = (T) elements[i];
if (predicate.test(value)) {
result.add(value);
}
}
return result;
}
@Override
public void forEach(Action<? super T> action) {
if (action == null) {
throw new IllegalArgumentException("null argument");
}
for (int i = 0; i < size; i++) {
@SuppressWarnings("unchecked")
T value = (T) elements[i];
action.consume(value);
}
}
@Override
public T reduce(T identity, BinaryFunction<T, T, T> accumulator) {
if (accumulator == null) {
throw new IllegalArgumentException("null argument");
}
T result = identity;
for (int i = 0; i < size; i++) {
@SuppressWarnings("unchecked")
T value = (T) elements[i];
result = accumulator.apply(result, value);
}
return result;
}
@Override
public int size() {
return size;
}
@Override
public boolean isEmpty() {
return size == 0;
}
/* =============================================================
* Object overrides
* ============================================================= */
@Override
public boolean equals(Object other) {
if (this == other) {
return true;
}
if (!(other instanceof List<?>)) {
return false;
}
List<?> o = (List<?>) other;
if (o.size() != this.size) {
return false;
}
for (int i = 0; i < size; i++) {
if (!java.util.Objects.equals(this.get(i), o.get(i))) {
return false;
}
}
return true;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append('[');
for (int i = 0; i < size; i++) {
sb.append(String.valueOf(elements[i]));
if (i < size - 1) {
sb.append(',');
}
}
sb.append(']');
return sb.toString();
}
}
Anonymous class and interface example
Step 1
Main.java
import java.util.LinkedList;
import java.util.List;
public class Main {
public static void main(String[] args) {
List<Integer> numbers = new LinkedList<>();
numbers.add(2);
numbers.add(8);
numbers.add(-2);
numbers.add(0);
numbers.add(18);
numbers.add(1);
numbers.add(3);
numbers.add(7);
System.out.println(numbers.toString());
sort(numbers);
System.out.println(numbers.toString());
}
public static <T extends Comparable<? super T>> void sort(List<T> values) {
assert values != null : "values cannot be null";
if (values.size() > 2) {
for (int sorted = 0; sorted < values.size(); sorted++) {
int indexOfMax = maximumIndexFrom(values, sorted);
swap(values, sorted, indexOfMax);
}
}
}
private static <T extends Comparable<? super T>> int maximumIndexFrom(List<T> values, int from) {
assert values != null : "values cannot be null";
assert values.size() > 0 : "values cannot be empty";
assert from >= 0 && from < values.size() : "from must be a valid index";
int maxIndex = from;
T max = values.get(from);
for (int i = from + 1; i < values.size(); i++) {
T current = values.get(i);
if (current.compareTo(max) > 0) {
max = current;
maxIndex = i;
}
}
return maxIndex;
}
private static <T> void swap(List<T> values, int a, int b) {
assert values != null : "values cannot be null";
assert values.size() > 0 : "values cannot be empty";
assert a >= 0 && a < values.size() : "a must be a valid index";
assert b >= 0 && b < values.size() : "b must be a valid index";
T valueAtA = values.get(a);
T valueAtB = values.get(b);
values.set(a, valueAtB);
values.set(b, valueAtA);
}
}
Step 2
Main.java
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
public class Main {
public static void main(String[] args) {
List<Integer> numbers = new LinkedList<>();
numbers.add(2);
numbers.add(8);
numbers.add(-2);
numbers.add(0);
numbers.add(18);
numbers.add(1);
numbers.add(3);
numbers.add(7);
System.out.println(numbers.toString());
sort(numbers, new Comparator<Integer>() {
@Override
public int compare(Integer a, Integer b) {
return a - b;
}
});
System.out.println(numbers.toString());
}
public static <T> void sort(List<T> values, Comparator<? super T> comparator) {
assert values != null : "values cannot be null";
if (values.size() > 2) {
for (int sorted = 0; sorted < values.size(); sorted++) {
int indexOfMax = maximumIndexFrom(values, sorted, comparator);
swap(values, sorted, indexOfMax);
}
}
}
private static <T> int maximumIndexFrom(List<T> values, int from, Comparator<? super T> comparator) {
assert values != null : "values cannot be null";
assert values.size() > 0 : "values cannot be empty";
assert from >= 0 && from < values.size() : "from must be a valid index";
int maxIndex = from;
T max = values.get(from);
for (int i = from + 1; i < values.size(); i++) {
T current = values.get(i);
if (comparator.compare(current, max) > 0) {
max = current;
maxIndex = i;
}
}
return maxIndex;
}
private static <T> void swap(List<T> values, int a, int b) {
assert values != null : "values cannot be null";
assert values.size() > 0 : "values cannot be empty";
assert a >= 0 && a < values.size() : "a must be a valid index";
assert b >= 0 && b < values.size() : "b must be a valid index";
T valueAtA = values.get(a);
T valueAtB = values.get(b);
values.set(a, valueAtB);
values.set(b, valueAtA);
}
}
Step 3
/function/Function.java
package functions;
public interface Function<A, B> {
public B apply(A source);
default <C> Function<C, B> compose(Function<C, A> before) { //it should be ? super C, ? extends A
if (before == null) {
throw new IllegalArgumentException("null argument");
}
final Function<A, B> f = this;
return new Function<C, B>() {
@Override
public B apply(C source) {
return f.apply(before.apply(source));
}
};
}
default <C> Function<A, C> andThen(Function<B, C> g) { //it should be ? super B, ? extends C
if (g == null) {
throw new IllegalArgumentException("null argument");
}
final Function<A, B> f = this;
return new Function<A, C>() {
@Override
public C apply(A source) {
return g.apply(f.apply(source));
}
};
}
}
Main.java
import java.util.LinkedList;
import java.util.List;
import functions.Function;
public class Main {
public static void main(String[] args) {
List<Integer> numbers = new LinkedList<>();
numbers.add(2);
numbers.add(8);
numbers.add(-2);
numbers.add(0);
numbers.add(18);
numbers.add(1);
numbers.add(3);
numbers.add(7);
System.out.println(numbers.toString());
List<Integer> negatives = new LinkedList<>();
Function<Integer, Integer> negative = new Function<Integer, Integer>() {
@Override
public Integer apply(Integer source) {
if (source == null) {
throw new IllegalArgumentException("source is null");
}
return -1 * source;
}
};
for (Integer e : numbers) {
negatives.add(negative.apply(e));
}
System.out.println(negatives.toString());
}
}
Step 4
/function/Function.java
package functions;
public interface Function<A, B> {
public B apply(A source);
default <C> Function<C, B> compose(Function<C, A> before) { //it should be ? super C, ? extends A
if (before == null) {
throw new IllegalArgumentException("null argument");
}
final Function<A, B> f = this;
return new Function<C, B>() {
@Override
public B apply(C source) {
return f.apply(before.apply(source));
}
};
}
default <C> Function<A, C> andThen(Function<B, C> g) { //it should be ? super B, ? extends C
if (g == null) {
throw new IllegalArgumentException("null argument");
}
final Function<A, B> f = this;
return new Function<A, C>() {
@Override
public C apply(A source) {
return g.apply(f.apply(source));
}
};
}
}
Main.java
import java.util.LinkedList;
import java.util.List;
import functions.Function;
public class Main {
public static void main(String[] args) {
List<Integer> numbers = new LinkedList<>();
numbers.add(2);
numbers.add(8);
numbers.add(-2);
numbers.add(0);
numbers.add(18);
numbers.add(1);
numbers.add(3);
numbers.add(7);
System.out.println(numbers.toString());
List<String> negativesAsString = new LinkedList<>();
Function<Integer, Integer> negative = new Function<Integer, Integer>() {
@Override
public Integer apply(Integer source) {
if (source == null) {
throw new IllegalArgumentException("source is null");
}
return -1 * source;
}
};
Function<Integer, String> asString = new Function<Integer,String>() {
@Override
public String apply(Integer source) {
return String.valueOf(source);
}
};
Function<Integer, String> toNegativeString = asString.compose(negative);
for (Integer e : numbers) {
negativesAsString.add(toNegativeString.apply(e));
}
System.out.println(negativesAsString.toString());
}
}
Step 5
/function/Function.java
package functions;
@FunctionalInterface
public interface Function<A, B> {
public B apply(A source);
default <C> Function<C, B> compose(Function<C, A> before) { //it should be ? super C, ? extends A
if (before == null) {
throw new IllegalArgumentException("null argument");
}
return (C t) -> apply(before.apply(t));
}
default <C> Function<A, C> andThen(Function<B, C> g) { //it should be ? super B, ? extends C
if (g == null) {
throw new IllegalArgumentException("null argument");
}
return (A t) -> g.apply(apply(t));
}
}
Main.java
import java.util.LinkedList;
import java.util.List;
import functions.Function;
public class Main {
public static void main(String[] args) {
List<Integer> numbers = new LinkedList<>();
numbers.add(2);
numbers.add(8);
numbers.add(-2);
numbers.add(0);
numbers.add(18);
numbers.add(1);
numbers.add(3);
numbers.add(7);
System.out.println(numbers.toString());
List<String> negativesAsString = new LinkedList<>();
Function<Integer, Integer> negative = (Integer v) -> {return -1 * v;};
Function<Integer, String> intAsString = (Integer v) -> {return String.valueOf(v);};
Function<Integer, String> toNegativeString = intAsString.compose(negative);
for (Integer e : numbers) {
negativesAsString.add(toNegativeString.apply(e));
}
System.out.println(negativesAsString.toString());
}
}
Step 6
Main.java
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
public class Main {
public static void main(String[] args) {
List<Integer> numbers = new LinkedList<>();
numbers.add(2);
numbers.add(8);
numbers.add(-2);
numbers.add(0);
numbers.add(18);
numbers.add(1);
numbers.add(3);
numbers.add(7);
System.out.println(numbers.toString());
sort(numbers, (Integer a, Integer b) -> {return a - b;});
System.out.println(numbers.toString());
}
public static <T> void sort(List<T> values, Comparator<? super T> comparator) {
assert values != null : "values cannot be null";
if (values.size() > 2) {
for (int sorted = 0; sorted < values.size(); sorted++) {
int indexOfMax = maximumIndexFrom(values, sorted, comparator);
swap(values, sorted, indexOfMax);
}
}
}
private static <T> int maximumIndexFrom(List<T> values, int from, Comparator<? super T> comparator) {
assert values != null : "values cannot be null";
assert values.size() > 0 : "values cannot be empty";
assert from >= 0 && from < values.size() : "from must be a valid index";
int maxIndex = from;
T max = values.get(from);
for (int i = from + 1; i < values.size(); i++) {
T current = values.get(i);
if (comparator.compare(current, max) > 0) {
max = current;
maxIndex = i;
}
}
return maxIndex;
}
private static <T> void swap(List<T> values, int a, int b) {
assert values != null : "values cannot be null";
assert values.size() > 0 : "values cannot be empty";
assert a >= 0 && a < values.size() : "a must be a valid index";
assert b >= 0 && b < values.size() : "b must be a valid index";
T valueAtA = values.get(a);
T valueAtB = values.get(b);
values.set(a, valueAtB);
values.set(b, valueAtA);
}
}
Figure example
Coord2D.java
package figures;
public class Coord2D
{
public static final Coord2D ZERO = new Coord2D(0.0f, 0.0f);
private double x;
private double y;
public Coord2D(double x, double y)
{
this.x = x;
this.y = y;
}
public double getX()
{
return x;
}
public double getY()
{
return y;
}
@Override
public String toString()
{
return "(" + x + ", " + y + ")";
}
}
Circle.java
package figures;
public class Circle extends Figure
{
private double radius;
public Circle(double radius)
{
super();
this.radius = radius;
}
public Circle(Coord2D center, double radius)
{
super(center);
this.radius = radius;
}
public double area()
{
return Math.PI * Math.pow(radius, 2.0f);
}
public double perimeter()
{
return 2.0f * Math.PI * radius;
}
@Override
public String toString()
{
return "I'm a circle, my center is at " + center.toString() +
"\n\tI have a radius of " + radius +
"\n\tMy area is " + area() +
"\n\tMy perimeter is " + perimeter();
}
}
Figure.java
package figures;
public abstract class Figure
{
protected Coord2D center;
public Figure()
{
center = Coord2D.ZERO;
}
public Figure(Coord2D center)
{
this.center = center;
}
public Coord2D getCenter()
{
return center;
}
public abstract double area();
public abstract double perimeter();
public double volumeByExtension(double height)
{
return area() * height;
}
@Override
public abstract String toString();
}
Main.java
import figures.*;
/**
* This first iteration of figures, shows how each Figure instance (Circle, Rectangle, or Square) will call its own toString() method.
*
* In this example you can also see that {@link Figure#volumeByExtension(double)} will be called on class Figure, but the area method
* will be called on the corresponding implementing class according to the specific instance (Circle, Rectangle, or Square)
*
* Finally, the maximum method is able to work because the type int supports the operator >
*
* In the next iteration we will try to use maximum on specific Figures.
*/
public class Main {
public static void main(String[] args) {
Figure[] figures = new Figure[] {new Circle(2.0d), new Rectangle(2.0d, 3.0d), new Square(3.0d), new Circle(4.2d)};
for (Figure figure : figures) {
System.out.println(figure.toString());
System.out.println("Volume by extension (by 3.2d): " + figure.volumeByExtension(3.2d));
}
int[] numbers = new int[] {2, 5, 42, 79, -10, 5, 9, 0, -13, 128};
System.out.println("The maximum number is: " + maximum(numbers));
}
public static int maximum(int[] values) {
assert values.length > 0 : "values cannot be empty";
int max = values[0];
for (int i = 1; i < values.length; i++) {
if (values[i] > max) {
max = values[i];
}
}
return max;
}
}
Python
Task 1 Complete implementation of all functions in strings.py.
Task 2 Complete implementation of all functions in array_dictionary.py.
Task 3 Create an “interface” Dictionary and implement it with a list of tuples.
Task 4 Implement a program in Python called strings_stats.py that will take \(n\) strings as command-line arguments, the first one will be considered as the main string, the rest will be considered as targets.
The program must print:
-
The main string string, and it’s length (the format must be
( )). -
The targets, and the length of each one (the format must be a comma-separated list of
( )). -
For each target in targets, you must write a line with how many times it occurred in the main string (the format must be
occurred in ). -
For each target in targets, you must write a line with the percentage of occurrences in the main string (the format must be
occurred % in ). The occurrences_percentage must be calculated considering all target’s occurrences as 100%.
You must use the “interface” and one implementation of Dictionary to solve the previous task.
Task 5 Implement “figures” classes and a sort function based on the area of each figure (use a method compare_to).
Task 6 Can you have proper generic classes and methods in Python, justify?
dictionary.py
from __future__ import annotations
from abc import ABC, abstractmethod
from typing import List, Tuple, Optional
class Dictionary(ABC):
"""A minimal dictionary interface mapping *str* keys to *int* values."""
@abstractmethod
def keys(self) -> List[str]:
"""Returns all keys present in the dictionary."""
@abstractmethod
def values(self) -> List[int]:
"""Returns all values present in the dictionary."""
@abstractmethod
def key_exists(self, key: str) -> bool:
"""Checks whether *key* is present in the dictionary."""
@abstractmethod
def get_value(self, key: str) -> Optional[int]:
"""Returns the value associated with *key* or ``None`` when the key is absent."""
@abstractmethod
def set_value(self, key: str, value: int) -> Optional[int]:
"""Sets *value* for *key* and returns the previous value if the key existed."""
class ListDictionary(Dictionary):
"""Dictionary implementation backed by a list of ``(key, value)`` tuples.
The implementation purposefully avoids using ``append`` or ``break`` to comply
with the constraints communicated during the session.
"""
def __init__(self, initial: Optional[List[Tuple[str, int]]] = None):
# Initialize the backing storage in a more explicit (and readable) way.
if initial is None:
self._data: List[Tuple[str, int]] = []
else:
# Make a shallow copy to avoid external mutation side-effects.
self._data = initial[:]
# ---------------------------------------------------------------------
# Interface implementation
# ---------------------------------------------------------------------
def keys(self) -> List[str]:
return [k for k, _ in self._data]
def values(self) -> List[int]:
return [v for _, v in self._data]
def key_exists(self, key: str) -> bool:
for k, _ in self._data:
if k == key:
return True
return False
def get_value(self, key: str) -> Optional[int]:
for k, v in self._data:
if k == key:
return v
return None
def set_value(self, key: str, value: int) -> Optional[int]:
old: Optional[int] = None
found: bool = False
for idx in range(len(self._data)):
k, v = self._data[idx]
if k == key:
old = v
self._data[idx] = (key, value)
found = True # no *break* used
# If the key was not present, extend the list without using *append*
if not found:
self._data += [(key, value)]
return old
# ------------------------------------------------------------------
# Convenience dunder methods (optional but handy)
# ------------------------------------------------------------------
def __len__(self) -> int: # pragma: no cover (helper)
return len(self._data)
def __iter__(self): # pragma: no cover (helper)
return iter(self._data)
def __repr__(self) -> str: # pragma: no cover (helper)
return f"ListDictionary({self._data})"
figures.py
from __future__ import annotations
from abc import ABC, abstractmethod
from math import pi
from typing import List
class Figure(ABC):
"""Abstract geometric figure."""
# ---------- required API --------------------------------------------
@abstractmethod
def area(self) -> float: # pragma: no cover (abstract)
"""Returns the area of the figure."""
# ------------------------------------------------------------------
# Comparison helper – reused by *sort_figures*
# ------------------------------------------------------------------
def compare_to(self, other: "Figure") -> int:
diff: float = self.area() - other.area()
eps: float = 1e-9
if abs(diff) < eps:
return 0
return -1 if diff < 0 else 1
# Convenience so built-in ``sorted`` could be used if desired
def __lt__(self, other: "Figure") -> bool: # pragma: no cover (helper)
return self.compare_to(other) < 0
# Nicely printable representation
def __repr__(self) -> str: # pragma: no cover (helper)
return f"{self.__class__.__name__}(area={self.area():.2f})"
class Circle(Figure):
def __init__(self, radius: float):
assert radius >= 0, "Radius must be non-negative"
self.radius = radius
def area(self) -> float:
return pi * self.radius * self.radius
class Rectangle(Figure):
def __init__(self, width: float, height: float):
assert width >= 0 and height >= 0, "Dimensions must be non-negative"
self.width = width
self.height = height
def area(self) -> float:
return self.width * self.height
class Square(Rectangle):
def __init__(self, side: float):
super().__init__(side, side)
# ---------------------------------------------------------------------
# Sorting helper
# ---------------------------------------------------------------------
def sort_figures(figures: List[Figure]) -> List[Figure]:
# Work on a shallow copy to keep the original list intact
sorted_list: List[Figure] = figures[:]
n: int = len(sorted_list)
for i in range(n):
# Find index of the minimum element in [i, n)
min_idx: int = i
for j in range(i + 1, n):
if sorted_list[j].compare_to(sorted_list[min_idx]) < 0:
min_idx = j
# Swap positions if needed
if min_idx != i:
sorted_list[i], sorted_list[min_idx] = sorted_list[min_idx], sorted_list[i]
return sorted_list
list_dictionary.py
def keys(dictionary: list[(str, int)]) -> list[str]:
return [key for key, _ in dictionary]
def values(dictionary: list[(str, int)]) -> list[int]:
return [value for _, value in dictionary]
def key_exists(dictionary: list[(str, int)], key: str) -> bool:
for key_value in dictionary:
if key_value[0] == key:
return True
return False
def get_value(dictionary: list[(str, int)], key: str) -> int | None:
for key_value in dictionary:
if key_value[0] == key:
return key_value[1]
return None
def set_value(dictionary: list[(str, int)], key: str, value: int) -> int | None:
old_value: int | None = None
found: bool = False
for idx in range(len(dictionary)):
k, v = dictionary[idx]
if k == key:
old_value = v
dictionary[idx] = (key, value)
found = True # continue checking rest without breaking
# If key was not found, add new entry without using append
if not found:
dictionary += [(key, value)]
return old_value
string.py
def is_substring(haystack: str, needle: str) -> bool:
return index_of(haystack, needle) != -1
def is_subsequence(haystack: str, needle: str) -> bool:
# An empty needle is always a subsequence
if len(needle) == 0:
return True
# Traverse both strings maintaining a pointer for the needle
idx: int = 0 # pointer inside needle
for c in haystack:
if idx < len(needle) and c == needle[idx]:
idx += 1
if idx == len(needle):
return True
return False
def generate_all_substrings(string: str) -> list[str]:
n: int = len(string)
return [string[start:end] for start in range(n) for end in range(start + 1, n + 1)]
def generate_all_subsequences(string: str) -> list[str]:
# Recursive generation without using append or bitwise operations
if string == "":
return [""]
first_char: str = string[0]
rest_subsequences: list[str] = generate_all_subsequences(string[1:])
return rest_subsequences + [first_char + subseq for subseq in rest_subsequences]
def to_upper_case(string: str) -> str:
upper: str = ""
for c in string:
if 'a' <= c <= 'z':
upper += chr(ord(c) - 32)
else:
upper += c
return upper
def to_lower_case(string: str) -> str:
lower: str = ""
for c in string:
if 'A' <= c <= 'Z':
lower += chr(ord(c) + 32)
else:
lower += c
return lower
def reverse(string: str) -> str:
rev: str = ""
for c in string:
rev = c + rev
return rev
def count_substrings(string: str, substring: str) -> int:
if len(substring) == 0:
return 1
count: int = 0
target_index: int = index_of(string, substring)
while target_index != -1:
count = count + 1
string = string[target_index + len(substring)]
target_index = index_of(string, substring)
return count
def index_of(string: str, target: str) -> int:
assert string is not None
assert target is not None
if len(target) == 0:
return 0
if len(string) == 0:
return -1
if len(target) > len(string):
return -1
found: bool = False
idx: int = 0
remaining_length: int = len(string)
# My last index would be at len(string) - 1
# At the start, the length of available string is len(string) - idx
while not found and remaining_length >= len(target):
if starts_with(string[idx:], target):
found = True
else:
idx = idx + 1
remaining_length = remaining_length - 1
if not found:
return -1
return idx
def starts_with(string: str, target: str) -> bool:
assert string is not None
assert target is not None
if len(target) == 0:
return True
if len(string) == 0:
return False
for i in range(len(target)):
if string[i] != target[i]:
return False
return True
string_stats.py
from __future__ import annotations
import sys
from typing import List
import strings # re-use `index_of` helper
from dictionary import ListDictionary
def count_occurrences(text: str, sub: str) -> int:
if len(sub) == 0:
# Convention borrowed from the earlier `count_substrings` definition
return 1
cnt: int = 0
haystack: str = text
pos: int = strings.index_of(haystack, sub)
while pos != -1:
cnt += 1
haystack = haystack[pos + 1 :]
pos = strings.index_of(haystack, sub)
return cnt
def main(argv: List[str]) -> None:
if len(argv) < 3:
print("Usage: python strings_stats.py <main_string> <target1> <target2> ...")
sys.exit(1)
main_str: str = argv[1]
targets: List[str] = argv[2:]
# ------------------------------------------------------------------
# Collect statistics using the Dictionary interface
# ------------------------------------------------------------------
stats = ListDictionary()
for t in targets:
stats.set_value(t, count_occurrences(main_str, t))
total_occurrences: int = sum(stats.values())
# ------------------------------------------------------------------
# Output section 1: main string and its length
# ------------------------------------------------------------------
print(f"{main_str} ({len(main_str)})")
# ------------------------------------------------------------------
# Output section 2: targets and their lengths (comma-separated list)
# ------------------------------------------------------------------
targets_with_len = ", ".join(f"{t} ({len(t)})" for t in targets)
print(targets_with_len)
# ------------------------------------------------------------------
# Output section 3: raw occurrence counts per target
# ------------------------------------------------------------------
for t in targets:
occurrences = stats.get_value(t) or 0
print(f"{t} occurred {occurrences} in {main_str}")
# ------------------------------------------------------------------
# Output section 4: percentage of occurrences per target
# ------------------------------------------------------------------
for t in targets:
occurrences = stats.get_value(t) or 0
percentage = 0.0 if total_occurrences == 0 else (occurrences * 100) / total_occurrences
# Format percentage with two decimal places
print(f"{t} occurred {percentage:.2f}% in {main_str}")
if __name__ == "__main__":
main(sys.argv)
Assignment with = and copy constructor and destructor
Usually copy value, copy reference for objects (shallow copy by default).
Shllow copy: copy each field
- Double free issue
- It is good to override assignment operator.
1
#include <iostream>
class IntWrapper {
private:
int value;
public:
IntWrapper(int value): value(value) {
std::cout << "Constructor called" << std::endl;
};
IntWrapper(const IntWrapper& other): value(other.value) {
std::cout << "Copy constructor called" << std::endl;
};
~IntWrapper() {
std::cout << "not much to do here! (my value was " << value << ")" << std::endl;
}
void change_value(const int new_value) {
value = new_value;
}
friend std::ostream & operator << (std::ostream &out, const IntWrapper &c);
};
std::ostream & operator << (std::ostream &out, const IntWrapper &c) {
out << "Wrapping(" << c.value << ")";
return out;
}
int main() {
IntWrapper w_1(1);
IntWrapper w_2 = w_1;
IntWrapper w_3 = w_1;
w_3 = w_2; // this is an assignment
std::cout << w_1 << std::endl;
std::cout << w_2 << std::endl;
std::cout << w_3 << std::endl;
std::cout << "Now we change w_1" << std::endl;
w_1.change_value(42);
std::cout << w_1 << std::endl;
std::cout << w_2 << std::endl;
std::cout << w_3 << std::endl;
std::cout << "Now we restore w_1 and change w_3" << std::endl;
w_1.change_value(1);
w_3.change_value(42);
std::cout << w_1 << std::endl;
std::cout << w_2 << std::endl;
std::cout << w_3 << std::endl;
return 1;
}
2
#include <iostream>
class IntWrapper {
private:
int * value;
public:
IntWrapper(int value) {
this->value = new(int);
*this->value = value;
std::cout << "Constructor called" << std::endl;
};
IntWrapper(const IntWrapper& other): IntWrapper(*other.value) {};
~IntWrapper() {
std::cout << "Need to free value now! (my value was " << (*value) << ")" << std::endl;
delete(value);
}
void change_value(const int new_value) {
*value = new_value;
}
friend std::ostream & operator << (std::ostream &out, const IntWrapper &c);
};
std::ostream & operator << (std::ostream &out, const IntWrapper &c) {
out << "Wrapping(" << *(c.value) << ")";
return out;
}
int main() {
IntWrapper w_1(1);
IntWrapper w_2 = w_1;
IntWrapper w_3 = w_1;
w_3 = w_2; // this is an assignment
std::cout << w_1 << std::endl;
std::cout << w_2 << std::endl;
std::cout << w_3 << std::endl;
std::cout << "Now we change w_1" << std::endl;
w_1.change_value(42);
std::cout << w_1 << std::endl;
std::cout << w_2 << std::endl;
std::cout << w_3 << std::endl;
std::cout << "Now we restore w_1 and change w_3" << std::endl;
w_1.change_value(1);
w_3.change_value(42);
std::cout << w_1 << std::endl;
std::cout << w_2 << std::endl;
std::cout << w_3 << std::endl;
return 1;
}
3
#include <iostream>
class IntWrapper {
private:
int * value;
public:
IntWrapper(int value) {
this->value = new(int);
*this->value = value;
std::cout << "Constructor called" << std::endl;
};
IntWrapper(const IntWrapper& other): IntWrapper(*other.value) {};
~IntWrapper() {
std::cout << "Need to free value now! (my value was " << (*value) << ")" << std::endl;
delete(value);
}
void change_value(const int new_value) {
*value = new_value;
}
friend std::ostream & operator << (std::ostream &out, const IntWrapper &c);
IntWrapper& operator=(const IntWrapper& other) {
if (&other != this) {
*(this->value) = *(other.value);
}
return *this;
}
};
std::ostream & operator << (std::ostream &out, const IntWrapper &c) {
out << "Wrapping(" << *(c.value) << ")";
return out;
}
int main() {
IntWrapper w_1(1);
IntWrapper w_2 = w_1;
IntWrapper w_3 = w_1;
w_3 = w_2; // this is an assignment
std::cout << w_1 << std::endl;
std::cout << w_2 << std::endl;
std::cout << w_3 << std::endl;
std::cout << "Now we change w_1" << std::endl;
w_1.change_value(42);
std::cout << w_1 << std::endl;
std::cout << w_2 << std::endl;
std::cout << w_3 << std::endl;
std::cout << "Now we restore w_1 and change w_3" << std::endl;
w_1.change_value(1);
w_3.change_value(42);
std::cout << w_1 << std::endl;
std::cout << w_2 << std::endl;
std::cout << w_3 << std::endl;
return 1;
}
SinglyLinkedListWithCache.java
package collections;
import functions.Action;
import functions.BinaryFunction;
import functions.Function;
import functions.Predicate;
/**
* An singly-linked node implementation of a list, but with a node cache to reuse nodes.
* @see {@link collections.List}
* @version 0.1
*/
public class SinglyLinkedListWithCache<T> extends AbstractList<T> {
/**
* Head pointer for this list (may be {@code null} for an empty list}
*/
private Node<T> head;
/**
* Cached size of this list. Always non-negative.
*/
private int size;
/* =============================================================
* Node cache
* ============================================================= */
/**
* Head of the singly-linked list that acts as the node cache.
*/
private Node<T> cacheHead;
/**
* Number of nodes currently stored in the cache.
*/
private int cacheSize;
/**
* Maximum number of nodes that the cache will store. Once this capacity is
* reached, additional removed nodes will be allowed to be reclaimed by the
* garbage collector.
*/
private final int cacheCapacity;
/**
* Builds an empty list whose cache can hold up to {@code cacheCapacity}
* nodes.
*
* @param cacheCapacity maximum number of nodes to keep in the cache. A
* negative value is interpreted as <em>no cache</em>.
*/
public SinglyLinkedListWithCache(int cacheCapacity) {
if (cacheCapacity < 0) {
throw new IllegalArgumentException("cacheCapacity must be >= 0");
}
this.cacheCapacity = cacheCapacity;
this.head = null;
this.size = 0;
this.cacheHead = null;
this.cacheSize = 0;
}
/**
* Builds an empty list with a default cache capacity of {@code 100}
* nodes.
*/
public SinglyLinkedListWithCache() {
this(100);
}
// ---------------------------------------------------------------------
// Helper methods
// ---------------------------------------------------------------------
/**
* Pops a node from the cache, initialising it with the supplied value. If
* the cache is empty a brand-new node will be allocated.
*/
private Node<T> allocateNode(T value) {
if (cacheHead != null) {
Node<T> node = cacheHead;
cacheHead = cacheHead.getNext();
cacheSize--;
node.setValue(value);
node.setNext(null);
return node;
}
return new Node<>(value);
}
/**
* Adds the supplied node to the cache – provided the cache did not yet
* reach the pre-defined capacity. The node's value is cleared to help the
* garbage collector.
*/
private void cacheNode(Node<T> node) {
if (cacheSize >= cacheCapacity || node == null) {
return; // let the GC reclaim the node
}
node.setValue(null);
node.setNext(cacheHead);
cacheHead = node;
cacheSize++;
}
/**
* Returns the node located at a given index. Helper method that assumes
* the index is valid (0 ≤ index < size).
*/
private Node<T> nodeAt(int index) {
Node<T> current = head;
for (int i = 0; i < index; i++) {
current = current.getNext();
}
return current;
}
@Override
public T get(int i) {
if (i < 0 || i >= size) {
throw new IllegalArgumentException("index out of range");
}
return nodeAt(i).getValue();
}
@Override
public void add(T elem) {
add(elem, size); // append is just insert at the end
}
@Override
public void add(T elem, int i) {
if (i < 0 || i > size) {
throw new IllegalArgumentException("index out of range");
}
Node<T> newNode = allocateNode(elem);
if (i == 0) { // insert at head
newNode.setNext(head);
head = newNode;
} else {
Node<T> prev = nodeAt(i - 1);
newNode.setNext(prev.getNext());
prev.setNext(newNode);
}
size++;
}
@Override
public void remove(T elem) {
Node<T> prev = null;
Node<T> current = head;
while (current != null) {
if (java.util.Objects.equals(current.getValue(), elem)) {
if (prev == null) {
head = current.getNext();
} else {
prev.setNext(current.getNext());
}
size--;
cacheNode(current);
return;
}
prev = current;
current = current.getNext();
}
}
@Override
public void remove(int i) {
if (i < 0 || i >= size) {
throw new IllegalArgumentException("index out of range");
}
Node<T> removed;
if (i == 0) {
removed = head;
head = head.getNext();
} else {
Node<T> prev = nodeAt(i - 1);
removed = prev.getNext();
prev.setNext(removed == null ? null : removed.getNext());
}
size--;
cacheNode(removed);
}
@Override
public <E> List<E> map(Function<? super T, ? extends E> function) {
if (function == null) {
throw new IllegalArgumentException("null argument");
}
SinglyLinkedListWithCache<E> result = new SinglyLinkedListWithCache<>(cacheCapacity);
Node<T> current = head;
while (current != null) {
result.add(function.apply(current.getValue()));
current = current.getNext();
}
return result;
}
@Override
public boolean all(Predicate<? super T> predicate) {
if (predicate == null) {
throw new IllegalArgumentException("null argument");
}
Node<T> current = head;
while (current != null) {
if (!predicate.test(current.getValue())) {
return false;
}
current = current.getNext();
}
return true;
}
@Override
public boolean any(Predicate<? super T> predicate) {
if (predicate == null) {
throw new IllegalArgumentException("null argument");
}
Node<T> current = head;
while (current != null) {
if (predicate.test(current.getValue())) {
return true;
}
current = current.getNext();
}
return false;
}
@Override
public List<T> filter(Predicate<? super T> predicate) {
if (predicate == null) {
throw new IllegalArgumentException("null argument");
}
SinglyLinkedListWithCache<T> result = new SinglyLinkedListWithCache<>(cacheCapacity);
Node<T> current = head;
while (current != null) {
T value = current.getValue();
if (predicate.test(value)) {
result.add(value);
}
current = current.getNext();
}
return result;
}
@Override
public void forEach(Action<? super T> action) {
if (action == null) {
throw new IllegalArgumentException("null argument");
}
Node<T> current = head;
while (current != null) {
action.consume(current.getValue());
current = current.getNext();
}
}
@Override
public T reduce(T identity, BinaryFunction<T, T, T> accumulator) {
if (accumulator == null) {
throw new IllegalArgumentException("null argument");
}
T result = identity;
Node<T> current = head;
while (current != null) {
result = accumulator.apply(result, current.getValue());
current = current.getNext();
}
return result;
}
@Override
public int size() {
return size;
}
@Override
public boolean isEmpty() {
return size == 0;
}
// ---------------------------------------------------------------------
// java.lang.Object overrides
// ---------------------------------------------------------------------
@Override
public boolean equals(Object other) {
if (this == other) {
return true;
}
if (!(other instanceof List<?>)) {
return false;
}
List<?> o = (List<?>) other;
if (o.size() != this.size) {
return false;
}
for (int i = 0; i < size; i++) {
if (!java.util.Objects.equals(this.get(i), o.get(i))) {
return false;
}
}
return true;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append('[');
Node<T> current = head;
while (current != null) {
sb.append(String.valueOf(current.getValue()));
current = current.getNext();
if (current != null) {
sb.append(',');
}
}
sb.append(']');
return sb.toString();
}
}
Lambda Expression
import java.util.List;
public class Main {
public static Integer abs(Integer a) {
return a < 0? (-1 * a) : a;
}
public static Function<Integer, Integer> addition(Integer a) {
return (new AddToValue(a))::apply;
}
public static Function<Integer, Function<Integer, Integer>> maximumOfThree(Integer a) {
return (new MaximumOfTwoAgainstFixedValued(a))::apply;
}
public static void main(String[] args) {
//Absolute
Function<Integer, Integer> abs_wc = new Abs(); //Using a Class
Integer absRes_wc = abs_wc.apply(-42);
Function<Integer, Integer> abs_wac = new Function<Integer,Integer>() {
@Override
public Integer apply(Integer v) {
return v < 0? (-1 * v) : v;
}
}; //Using Anonymous Class
Integer absRes_wac = abs_wac.apply(-42);
Function<Integer, Integer> abs_wle = (Integer v) -> {return v < 0? (-1 * v) : v;};
//Using Lambda Expression
Integer absRec_wle = abs_wle.apply(-42);
Function<Integer, Integer> abs_wmr = Main::abs;
Function<Integer, Integer> identity = Integer::new;
//Addition (a + b = res)
Function<Integer, Function<Integer, Integer>> addition_wc = new Addition();
Integer res_wc = addition_wc.apply(2).apply(3);
Function<Integer, Function<Integer, Integer>> addition_wac = new Function<Integer,Function<Integer,Integer>>() {
@Override
public Function<Integer, Integer> apply(Integer a) {
return new Function<Integer,Integer>() {
@Override
public Integer apply(Integer b) {
return a + b;
}
};
}
}; //With Anonymous Class
Integer res_wac = addition_wac.apply(2).apply(3);
Function<Integer, Function<Integer, Integer>> addition_wle_1 =
(Integer a) -> (Integer b) -> {return a + b;};
Function<Integer, Function<Integer, Integer>> addition_wle_2 =
(Integer a) -> {return (Integer b) -> {return a + b;};};
Integer res_wle = addition_wle_1.apply(2).apply(3);
Function<Integer, Function<Integer, Integer>> addition_wmr = Main::addition;
Integer res_wmr = addition_wmr.apply(2).apply(3);
//Maximum of three
Function<Integer, Function<Integer, Function<Integer, Integer>>> maxThree_wc = new MaximumOfThree();
System.out.println("Maximum of 3, 1, 2 is " + maxThree_wc.apply(3).apply(1).apply(2));
Function<Integer, Function<Integer, Function<Integer, Integer>>> maxThree_wac = new Function<Integer,Function<Integer,Function<Integer,Integer>>>() {
@Override
public Function<Integer, Function<Integer, Integer>> apply(Integer a) {
return new Function<Integer,Function<Integer,Integer>>() {
@Override
public Function<Integer,Integer> apply(Integer b) {
return new Function<Integer,Integer>() {
@Override
public Integer apply(Integer c) {
if (a >= b && a >= c) {
return a;
} else if (b >= a && b >= c) {
return b;
} else {
return c;
}
}
};
}
};
}
};
System.out.println("Maximum of 3, 1, 2 is " + maxThree_wac.apply(3).apply(1).apply(2));
Function<Integer, Function<Integer, Function<Integer, Integer>>> maxThree_wle =
(Integer a) -> (Integer b) -> (Integer c) -> {
if (a >= b && a >= c) {
return a;
} else if (b >= a && b >= c) {
return b;
} else {
return c;
}
};
Function<Integer, Function<Integer, Function<Integer, Integer>>> maxThree_wmr = Main::maximumOfThree;
Function<List<Integer>, Function<Integer, Integer>> listGet_wc = new ListGet();
Function<List<Integer>, Function<Integer, Integer>> listGet_wax = new Function<List<Integer>,Function<Integer,Integer>>() {
@Override
public Function<Integer, Integer> apply(List<Integer> l) {
return new Function<Integer,Integer>() {
@Override
public Integer apply(Integer index) {
return l.get(index);
}
};
}
};
Function<List<Integer>, Function<Integer, Integer>> listGet_wle =
(List<Integer> l) -> (Integer index) -> {return l.get(index);};
Function<List<Integer>, Function<Integer, Integer>> listGet_wmr =
(List<Integer> l) -> {return l::get;};
Function<Integer, Integer> factorial =
(Integer n) -> {
Integer res = 1;
for (int i = n; i > 0; i--) {
res *= i;
}
return res;
};
Integer res_factorial = factorial.apply(3);
System.out.println(res_factorial);
}
}