Practical example
Argument, package, precondition, postcondition, invariants, exception
Main.java
import Person.Person;
public class Main {
public static void main(String[] args) {
//print the arguments
for (String arg : args) {
System.out.print(arg);
}
System.out.print(args.length);
//create 4 persons
Person PersonA = new Person("John", "Wick", 60, 420000047);
Person PersonB = new Person("Wick", "John", 60, 420000047);
Person PersonC = new Person("Wohn", "Jick", 60, 420000048);
Person PersonAClone = new Person("John", "Wick", 60, 420000047);
System.out.println(PersonA.toString());
System.out.println(PersonB.toString());
System.out.println(PersonC.toString());
System.out.println(
PersonA.toString() + " == " + PersonAClone.toString() + "? " +
(PersonA == PersonAClone));
System.out.println(
PersonA.toString() + ".equals(" + PersonAClone.toString() + ")? " +
PersonA.equals(PersonAClone));
}
}
---
output
0
Person {name=John, surname=Wick, age=60, id=420000047}
Person {name=Wick, surname=John, age=60, id=420000047}
Person {name=Wohn, surname=Jick, age=60, id=420000048}
Person {name=John, surname=Wick, age=60, id=420000047}
== Person {name=John, surname=Wick, age=60, id=420000047}? false
Person {name=John, surname=Wick, age=60, id=420000047}.equals
(Person {name=John, surname=Wick, age=60, id=420000047})? true
Person/Person.java
package Person;
/**
* This class represents a Person with name, surname, age, and id.
* Invariant:
* <ul>
* <li>name and surname cannot be null.</li>
* <li>name and surname cannot be empty.</li>
* <li>name and surname can only contain letters.</li>
* <li>name and surname must be capitalized.</li>
* <li>age must be greater than zero (0).</li>
* <li>id cannot start with a zero (0), and must have exactly 9 digits.</li>
* </ul>
*/
public class Person {
private static final int HUNDRED_MILLON = 100000000;
private String name;
private String surname;
private int age;
private int id;
/**
* Constructs a new Person.
* @param name the name of the Person
* @param surname the surname of the Person.
* @param age the age of the Person.
* @param id the id of the Person.
* preconditions:
* <ul>
* <li>name and surname cannot be null.</li>
* <li>name and surname cannot be empty.</li>
* <li>name and surname can only contain letters.</li>
* <li>name and surname must be capitalized.</li>
* <li>age must be greater than zero (0).</li>
* <li>id cannot start with a zero (0), and must have exactly 9 digits.</li>
* </ul>
*/
public Person(String name, String surname, int age, int id) {
if (!validateString(name)) {
throw new IllegalArgumentException("invalid name.");
}
if (!validateString(surname)) {
throw new IllegalArgumentException("invalid surname.");
}
if (age < 1) {
throw new IllegalArgumentException("age not positive (greater than zero).");
}
if ((id - HUNDRED_MILLON) < 0) {
throw new IllegalArgumentException("id has less than 9 digits.");
}
this.name = name;
this.surname = surname;
this.age = age;
this.id = id;
if (!repOk()) {
throw new IllegalStateException("Invariant violated");
}
}
/**
* @return the name of the Person
*/
public String getName() {
if (!repOk()) {
throw new IllegalStateException("Invariant violated");
}
return name;
}
/**
* @return the surname of the Person
*/
public String getSurname() {
if (!repOk()) {
throw new IllegalStateException("Invariant violated");
}
return surname;
}
/**
* @return the age of the Person
*/
public int getAge() {
if (!repOk()) {
throw new IllegalStateException("Invariant violated");
}
return age;
}
/**
* @return the id of the Person
*/
public int getId() {
if (!repOk()) {
throw new IllegalStateException("Invariant violated");
}
return id;
}
//TODO: complete with setter methods, i.e.: methods to set new values for each field.
/**
* @return a representation of this Person
*/
@Override
public String toString() {
return "Person {name=" + name +
", surname=" + surname +
", age=" + age +
", id=" + id + "}";
}
/**
* @param other the object to compare with
* @return {@code true} iff this Person is equal to other.
*/
@Override
public boolean equals(Object other) {
if (other == null) {
return false;
}
if (!(other instanceof Person)) {
return false;
}
Person otherAsPerson = (Person) other;
if (!name.equals(otherAsPerson.name)) {
return false;
}
if (!surname.equals(otherAsPerson.surname)) {
return false;
}
if (age != otherAsPerson.age) {
return false;
}
return id == otherAsPerson.id;
}
/**
* @return {@code true} iff the invariant is satisfied.
*/
public boolean repOk() {
if (!validateString(name)) {
return false;
}
if (!validateString(surname)) {
return false;
}
if (age < 1) {
return false;
}
return (id - HUNDRED_MILLON) >= 0;
}
private boolean validateString(String string) {
if (string == null) {
return false;
}
if (string.trim().isEmpty()) {
return false;
}
if (string.length() != string.trim().length()) {
return false;
}
if (!string.substring(0, 1).toUpperCase().equals(string.substring(0, 1))) {
//substring(int beginIndex, int endIndex)
return false;
}
return true;
}
}
Junit test for above program
package Person;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
class PersonTest {
@Test
void testValidPersonCreationAndGetters() {
System.out.println("Running testValidPersonCreationAndGetters...");
// Arrange (specific inputs for this test)
String expectedName = "Alice";
String expectedSurname = "Smith";
int expectedAge = 25;
int expectedId = 987654321;
// Act
Person newPerson = new Person(expectedName, expectedSurname, expectedAge, expectedId);
// Assert
assertNotNull(newPerson, "Person object should not be null after valid construction.");
// Verify toString() output
String expectedToString = "Person {name=Alice, surname=Smith, age=25, id=987654321}";
assertEquals(expectedToString, newPerson.toString(), "toString() should return the expected formatted string.");
// Verify that the invariant holds for the valid object
assertTrue(newPerson.repOk(), "repOk() should be true for a valid Person object.");
}
@Test
void testConstructor_NullName_Negative() {
System.out.println("Running testConstructor_NullName_Negative...");
// Act & Assert
IllegalArgumentException thrown = assertThrows(
IllegalArgumentException.class,
() -> new Person(null, "Doe", 30, 123456789),
"Expected IllegalArgumentException for null name."
);
assertEquals("invalid name.", thrown.getMessage(), "Exception message mismatch for null name.");
System.out.println("testConstructor_NullName_Negative finished successfully.");
}
Inheritance, interface.... Generic
Java one example
List.java
package Task1_2;
public interface List<E> {
//appends a value to the list
void append(E value);
//returns the element at a valid index
E at(int index);
//removes an element at a valid index
void remove(int index);
//filters all elements that satisfies the predicate
List<E> filter(Function<E, Boolean> predicate);
//maps a function to all elements and return a list with the results
<T> List<T> map(Function<E, T> mappingFunction);
//educes all elements in a list to one value by using a binary function
E reduce(Function<E, Function<E, E>> binaryFunction, E neutralValue);
//return the first index of an element that satisfies the predicate
Optional<Integer> indexOf(Function<E, Boolean> predicate);
}
AbstractList.java
package Task1_2;
public abstract class AbstractList<E> implements List<E> {
//appends a value to the list
public abstract void append(E value);
//returns the element at a valid index
public abstract E at(int index);
//removes an element at a valid index
public abstract void remove(int index);
//returns the number of elements in the list
protected abstract int size();
//returns a new empty list instance parameterized by U
protected abstract <U> List<U> newList();
//filters all elements that satisfies the predicate
public List<E> filter(Function<E, Boolean> predicate) {
List<E> result = newList();
for (int i = 0; i < size(); i++) {
E element = at(i);
if (predicate.apply(element)) {
result.append(element);
}
}
return result;
}
//maps a function to all elements and return a list with the results
public <T> List<T> map(Function<E, T> mappingFunction) {
List<T> result = newList();
for (int i = 0; i < size(); i++) {
result.append(mappingFunction.apply(at(i)));
}
return result;
}
//educes all elements in a list to one value by using a binary function
public E reduce(Function<E, Function<E, E>> binaryFunction, E neutralValue) {
E result = neutralValue;
for (int i = 0; i < size(); i++) {
E element = at(i);
result = binaryFunction.apply(result).apply(element);
}
return result;
}
//return the first index of an element that satisfies the predicate
public Optional<Integer> indexOf(Function<E, Boolean> predicate) {
for (int i = 0; i < size(); i++) {
if (predicate.apply(at(i))) {
return Optional.of(i);
}
}
return Optional.empty();
}
}
LinkedList.java
package Task1_2;
public class LinkedList<E> extends AbstractList<E> {
// Node class for singly linked list
private static class Node<E> {
E data;
Node<E> next;
Node(E data) {
this.data = data;
this.next = null;
}
}
private Node<E> head;
private Node<E> tail;
private int size = 0;
public LinkedList() {
head = null;
tail = null;
size = 0;
}
@Override
public void append(E value) {
Node<E> newNode = new Node<>(value);
if (head == null) {
head = newNode;
tail = newNode;
} else {
tail.next = newNode;
tail = newNode;
}
size++;
}
@Override
public E at(int index) {
if (index < 0 || index >= size) {
throw new IndexOutOfBoundsException("Index out of bounds: " + index);
}
Node<E> current = head;
for (int i = 0; i < index; i++) {
current = current.next;
}
return current.data;
}
@Override
public void remove(int index) {
if (index < 0 || index >= size) {
throw new IndexOutOfBoundsException("Index out of bounds: " + index);
}
if (index == 0) {
head = head.next;
if (head == null) {
tail = null;
}
} else {
Node<E> prev = head;
for (int i = 0; i < index - 1; i++) {
prev = prev.next;
}
Node<E> removed = prev.next;
prev.next = removed.next;
if (removed == tail) {
tail = prev;
}
}
size--;
}
@Override
protected int size() {
return size;
}
@Override
protected <U> List<U> newList() {
return new LinkedList<>();
}
}
Optional.java
package Task1_2;
public class Optional<E> {
private final E value;
private Optional(E value) {
this.value = value;
}
public static <T> Optional<T> of(T value) {
return new Optional<>(value);
}
public static <T> Optional<T> empty() {
return new Optional<>(null);
}
public boolean isPresent() {
return value != null;
}
public E get() {
if (value == null) {
throw new java.util.NoSuchElementException();
}
return value;
}
}
Function.java
package Task1_2;
@FunctionalInterface
public interface Function<A, B> {
B apply(A a);
}
Main.java
package Task1_2;
public class Main {
public static void main(String[] args) {
// Create a LinkedList of Integers
LinkedList<Integer> list = new LinkedList<>();
System.out.println("Appending values 1 to 5");
for (int i = 1; i <= 5; i++) {
list.append(i);
}
// Print size and elements
System.out.println("List size: " + list.size());
System.out.print("List elements: ");
for (int i = 0; i < list.size(); i++) {
System.out.print(list.at(i) + " ");
}
System.out.println();
// Access element at index 2
System.out.println("Element at index 2: " + list.at(2));
// Remove element at index 2
System.out.println("Removing element at index 2");
list.remove(2);
System.out.print("List after removal: ");
for (int i = 0; i < list.size(); i++) {
System.out.print(list.at(i) + " ");
}
System.out.println();
// Filter even numbers
System.out.println("Filtering even numbers:");
LinkedList<Integer> evens = (LinkedList<Integer>) list.filter(e -> e % 2 == 0);
System.out.print("Evens: ");
for (int i = 0; i < evens.size(); i++) {
System.out.print(evens.at(i) + " ");
}
System.out.println();
// Map to squares
System.out.println("Mapping to squares:");
LinkedList<Integer> squares = (LinkedList<Integer>) list.map(e -> e * e);
System.out.print("Squares: ");
for (int i = 0; i < squares.size(); i++) {
System.out.print(squares.at(i) + " ");
}
System.out.println();
// Reduce to sum
int sum = list.reduce(acc -> elem -> acc + elem, 0);
System.out.println("Sum of elements: " + sum);
// Index of existing element
Optional<Integer> idx = list.indexOf(e -> e == 4);
if (idx.isPresent()) {
System.out.println("Index of 4: " + idx.get());
} else {
System.out.println("4 not found");
}
// Index of non-existing element
Optional<Integer> missing = list.indexOf(e -> e == 100);
if (missing.isPresent()) {
System.out.println("Index of 100: " + missing.get());
} else {
System.out.println("100 not found");
}
}
}
Task1,2
Task1
Java
/**
* Implement a function that returns the maximum value of a non-empty array of integer values.
* The implementation must be done in C++, Java, and Python.
*/
public class Task1 {
public static int maximum(int[] values) {
assert(values.length > 0);
int max = values[0];
for (int i = 1; i < values.length; i++) {
if (values[i] > max) {
max = values[i];
}
}
return max;
}
private static String toString(int[] values) {
StringBuilder sb = new StringBuilder("[");
for (int i = 0; i < values.length; i++) {
sb.append(values[i]);
if (i + 1 < values.length) {
sb.append(", ");
}
}
sb.append("]");
return sb.toString();
}
public static void main(String[] args) {
int values[] = new int[args.length];
int i = 0;
for (String arg : args) {
values[i++] = Integer.valueOf(arg);
}
System.out.print("The maximum value of " + toString(values));
System.out.println(" is: " + maximum(values));
}
}
Python
"""
Implement a function that returns the maximum value of a non-empty array of integer values.
The implementation must be done in C++, Java, and Python.
"""
def maxOfArray(arr : list[int]) -> int:
assert(len(values) > 0)
max: int = values[0]
for value in values[1:]:
if value > max:
max = value
return max
if __name__ == "__main__":
import sys
assert(len(sys.argv) > 1)
values: list[int] = []
for argv in sys.argv[1:]:
values.append(int(argv))
print("The maximum value of {} is: {}".format(values, maximum(values)))
string_values = ["Can", "I", "do", "this?"]
print("The maximum value of {} is: {}".format(string_values, maximum(string_values)))
tuples_values = [("Is", 1), ("Derp", 42), ("a", 2), ("cool", 3), ("number?", 4)]
print("The maximum value of {} is: {}".format(tuples_values, maximum(tuples_values)))
C++
/**
* Implement a function that returns the maximum value of a non-empty array of integer values.
* The implementation must be done in C++, Java, and Python.
*/
#include <iostream>
#include <cassert>
int maximum(const int size, int values[]) {
assert(size > 0);
int max = values[0];
for (int i = 1; i < size; i++) {
if (values[i] > max) {
max = values[i];
}
}
return max;
}
void printArray(const int size, int values[]) {
std::cout << "[";
for (int i = 0; i < size; i++) {
std::cout << values[i];
if (i + 1 < size) {
std::cout << ", ";
}
}
std::cout << "]";
}
int main(const int argc, const char ** const argv) {
assert(argc > 1);
int size = argc - 1;
int values[size];
for (int i = 1; i < argc; i++) {
std::string arg = std::string(argv[i]);
values[i - 1] = std::stoi(arg);
}
std::cout << "The maximum value of ";
printArray(size, values);
std::cout << " is: " << maximum(size, values) << std::endl;
return 0;
}
Task2
Java
/**
*Implement a function that returns the maximum value
* of a non-empty generic array of values with type T
*/
import java.util.function.BiFunction;
public class Task2 {
public static <T> T maximum_f(T[] values, BiFunction<T, T, T> fmax) {
assert(values.length > 0);
T max = values[0];
for (int i = 1; i < values.length; i++) {
max = fmax.apply(max, values[i]);
}
return max;
}
public static <T extends Comparable<? super T>> T maximum_c(T[] values) {
//<T extends Comparable<? super T>> - More flexible
//Allows T to implement Comparable for itself OR any of its supertypes
//Uses a "lower bounded wildcard" (? super T)
//Also you can use Comparable<T> instead of Comparable<? super T>
assert(values.length > 0);
T max = values[0];
for (int i = 1; i < values.length; i++) {
if (values[i].compareTo(max) > 0) {
max = values[i];
}
}
return max;
}
private static <T> String toString(T[] values) {
StringBuilder sb = new StringBuilder("[");
for (int i = 0; i < values.length; i++) {
sb.append(String.valueOf(values[i]));
if (i + 1 < values.length) {
sb.append(", ");
}
}
sb.append("]");
return sb.toString();
}
public static void main(String[] args) {
Integer values[] = new Integer[args.length];
int i = 0;
for (String arg : args) {
values[i++] = Integer.valueOf(arg);
}
BiFunction<Integer, Integer, Integer> int_max = (Integer a, Integer b) -> {return a > b? a:b;};
System.out.print("The maximum value of (using a function) " + toString(values));
System.out.println(" is: " + maximum_f(values, int_max));
System.out.print("The maximum value of (using Comparable) " + toString(values));
System.out.println(" is: " + maximum_c(values));
}
}
Python
"""
Implement a function that returns the maximum value
of a non-empty generic array of values with type T
"""
from typing import TypeVar
T = TypeVar("T")
def maxOfArray(arr : list[T]) -> T:
max = arr[0]
for i in arr:
if(i > max):
max = i
return max
if __name__ == "__main__":
test_array = [3, 7, 2, 9, 1, 5]
print(f"Array: {test_array}")
max_value = maxOfArray(test_array)
print(f"Maximum value: {max_value}")
# Test with strings
string_array = ["apple", "zebra", "banana", "cherry"]
print(f"String array: {string_array}")
max_string = maxOfArray(string_array)
print(f"Maximum string: {max_string}")
C++
/**
*Implement a function that returns the maximum value
* of a non-empty generic array of values with type T
*/
#include <iostream>
#include <cassert>
class Person {
private:
std::string name;
int id;
public:
Person(): name("John"), id(0) {}
Person(std::string name, int id): name(name), id(id) {}
Person(const Person& other) {
this->name = other.name;
this->id = other.id;
}
~Person() {}
int getId() const {
return id;
}
int comparesTo(Person other) {
return this->id - other.id;
}
friend std::ostream& operator<<(std::ostream& os, const Person& person);
//friend keyword allows these functions to access private/protected members of the Person class
//std::ostream& is a reference to an output stream object
friend bool operator>(const Person& a, const Person& b) {
//With &. No copying - you work directly with the original object, faster and more memory efficient
return a.getId() > b.getId();
}
};
std::ostream& operator<<(std::ostream& os, const Person& person) {
os << "Person(" << person.id << ", " << person.name << ")";
return os;
}
template<typename T>
T maximum_t(const int size, T values[]) {
assert(size > 0);
T max = values[0];
for (int i = 1; i < size; i++) {
if (values[i] > max) {
max = values[i];
}
}
return max;
}
/////////////////////////////////////////////////////
template<typename T>
using t_max = T (*)(T, T);
int max(int a, int b) {
return a > b? a : b;
}
template<typename T>
T maximum_f(const int size, T values[], t_max<T> max_function) {
assert(size > 0);
T max = values[0];
for (int i = 1; i < size; i++) {
max = max_function(max, values[i]);
}
return max;
}
/////////////////////////////////////////////////////
template<typename T>
concept Comparable = requires(T a, T b) {
{a.comparesTo(b)} -> std::same_as<int>;
};
template<Comparable T>
T maximum_c(const int size, T values[]) {
assert(size > 0);
T max = values[0];
for (int i = 1; i < size; i++) {
if (values[i].comparesTo(max) > 0) {
max = values[i];
}
}
return max;
}
template<typename T>
void printArray(const int size, T values[]) {
std::cout << "[";
for (int i = 0; i < size; i++) {
std::cout << values[i];
if (i + 1 < size) {
std::cout << ", ";
}
}
std::cout << "]";
}
int main(const int argc, const char ** const argv) {
assert(argc > 1);
int size = argc - 1;
int values[size];
for (int i = 1; i < argc; i++) {
std::string arg = std::string(argv[i]);
values[i - 1] = std::stoi(arg);
}
std::cout << "The maximum value of (using template and >) ";
printArray(size, values);
std::cout << " is: " << maximum_t<int>(size, values) << std::endl;
std::cout << "The maximum value of (using a max function) ";
printArray(size, values);
std::cout << " is: " << maximum_f<int>(size, values, max) << std::endl;
// std::cout << "The maximum value of (using Comparable concept) ";
// printArray(size, values);
// std::cout << " is: " << maximum_c<int>(size, values, max) << std::endl;
Person persons[] = {Person("A", 1), Person("B", 2), Person("C", 3)};
std::cout << "The maximum value of (using template and >) ";
printArray(3, persons);
std::cout << " is: " << maximum_t<Person>(3, persons) << std::endl;
std::cout << "The maximum value of (using Comparable concept) ";
printArray(3, persons);
std::cout << " is: " << maximum_c<Person>(3, persons) << std::endl;
return 0;
}
Task3,4
Task3
Java
/**
* Implement a function that returns the most repeated value
* on a non-empty array of integer values.
*/
public class Task3 {
public static int maxIndexOfArray(int arr[]) {
int maxIndex = 0;
int size = arr.length;
for(int i = 0; i < size; i++) {
if(arr[i] > arr[maxIndex])
maxIndex = i;
}
return maxIndex;
}
public static int repeatedCount(int arr[]) {
int currentVar;
int size = arr.length;
int count[] = new int[size];//Note this
for(int i = 0; i < size; i++) {
int times = 0;
currentVar = arr[i];
for(int j = 0; j< size; j++) {
if(currentVar == arr[j])
times++;
}
count[i] = times;
}
return arr[maxIndexOfArray(count)];
}
public static void main(String[] args) {
int[] testArray = {1, 3, 2, 3, 4, 3, 2, 1, 3};
System.out.print("Array: ");
for(int num : testArray) {
System.out.print(num + " ");
}
System.out.println();
int mostRepeated = repeatedCount(testArray);
System.out.println("Most repeated value: " + mostRepeated);
}
}
Python
"""
Implement a function that returns the most repeated value
on a non-empty array of integer values.
"""
def maxIndexOfArray(arr : list[int]) -> int:
maxIndex = 0
size = len(arr)
for i in range(len(arr)):
if(arr[i] > arr[maxIndex]):
maxIndex = i
return maxIndex
def repeatedCount(arr : list[int]) -> int:
size = len(arr)
count = [0] * size #Note this
for i in range(size):
times = 0
currentVar = arr[i]
for j in range(size):
if currentVar == arr[j]:
times += 1
count[i] = times
return arr[maxIndexOfArray(count)]
if __name__ == "__main__":
test_array = [1, 3, 2, 3, 4, 3, 2, 1, 3]
print(f"Array: {test_array}")
most_repeated = repeatedCount(test_array)
print(f"Most repeated value: {most_repeated}")
C++
/**
* Implement a function that returns the most repeated value
* on a non-empty array of integer values.
*/
#include <iostream>
using namespace std;
int maxIndexOfArray(int arr[], int size) {
int maxIndex = 0;
for(int i = 0; i < size; i++) {
if(arr[i] > arr[maxIndex])
maxIndex = i;
}
return maxIndex;
}
int repeatedCount(int arr[], int size) {
int currentVar;
int count[size];
for(int i = 0; i < size; i++) {
int times = 0;
currentVar = arr[i];
for(int j = 0; j< size; j++) {
if(currentVar == arr[j])
times++;
}
count[i] = times;
}
return arr[maxIndexOfArray(count, size)];
}
int main() {
int testArray[] = {1, 3, 2, 3, 4, 3, 2, 1, 3};
int size = sizeof(testArray) / sizeof(testArray[0]);
cout << "Array: ";
for(int i = 0; i < size; i++) {
cout << testArray[i] << " ";
}
cout << endl;
int mostRepeated = repeatedCount(testArray, size);
cout << "Most repeated value: " << mostRepeated << endl;
return 0;
}
Task4
Java
/**
* Implement a function that returns the most repeated value
* on a non-empty generic array of values with type T
*/
public class Task4 {
public static <T extends Comparable<T>> T repeatedCount(T[] arr) {
T currentVar;
int size = arr.length;
int count[] = new int[size];//Note this
for(int i = 0; i < size; i++) {
int times = 0;
currentVar = arr[i];
for(int j = 0; j< size; j++) {
if(currentVar.compareTo(arr[j]) == 0)
times++;
}
count[i] = times;
}
return arr[maxIndexOfArray(count)];
}
public static int maxIndexOfArray(int[] arr) {
int maxIndex = 0;
int size = arr.length;
for(int i = 0; i < size; i++) {
if(arr[i] > (arr[maxIndex]))
maxIndex = i;
}
return maxIndex;
}
public static void main(String[] args) {
// Test with integers
Integer[] intArray = {1, 3, 2, 3, 4, 3, 2, 1, 3};
System.out.print("Integer array: ");
for(Integer num : intArray) {
System.out.print(num + " ");
}
System.out.println();
Integer mostRepeated = repeatedCount(intArray);
System.out.println("Most repeated integer: " + mostRepeated);
// Test with strings
String[] stringArray = {"apple", "banana", "apple", "cherry", "apple", "banana"};
System.out.print("String array: ");
for(String str : stringArray) {
System.out.print(str + " ");
}
System.out.println();
String mostRepeatedString = repeatedCount(stringArray);
System.out.println("Most repeated string: " + mostRepeatedString);
}
}
Python
"""
Implement a function that returns the most repeated value
on a non-empty generic array of values with type T
"""
from typing import TypeVar
T = TypeVar("T")
def maxIndexOfArray(arr : list[int]) -> int:
maxIndex = 0
size = len(arr)
for i in range(len(arr)):
if(arr[i] > arr[maxIndex]):
maxIndex = i
return maxIndex
def repeatedCount(arr : list[T]) -> T:
size = len(arr)
count = [0] * size #Note this
for i in range(size):
times = 0
currentVar = arr[i]
for j in range(size):
if currentVar == arr[j]:
times += 1
count[i] = times
return arr[maxIndexOfArray(count)]
if __name__ == "__main__":
# Test with integers
test_array = [1, 3, 2, 3, 4, 3, 2, 1, 3]
print(f"Integer array: {test_array}")
most_repeated = repeatedCount(test_array)
print(f"Most repeated value: {most_repeated}")
# Test with strings
string_array = ["apple", "banana", "apple", "cherry", "apple", "banana"]
print(f"String array: {string_array}")
most_repeated_string = repeatedCount(string_array)
print(f"Most repeated string: {most_repeated_string}")
C++
/**Implement a function that returns the most repeated value
* on a non-empty generic array of values with type T
*/
#include <concepts>
#include <iostream>
using namespace std;
template <typename T>
concept Comparable = requires(T a, T b) {
{ a.compares_to(b) } -> std::same_as<int>;
};
template<Comparable T>
int comparing(T a, T b) {
return a.compares_to(b);
}
int maxIndexOfArray(int arr[], int size) {
int maxIndex = 0;
for(int i = 0; i < size; i++) {
if(arr[i] > arr[maxIndex])
maxIndex = i;
}
return maxIndex;
}
template<Comparable T>
T repeatedCount(T arr[], int size) {
T currentVar;
int count[size];
for(int i = 0; i < size; i++) {
int times = 0;
currentVar = arr[i];
for(int j = 0; j < size; j++) {
if(comparing(currentVar, arr[j]) == 0)
times++;
}
count[i] = times;
}
return arr[maxIndexOfArray(count, size)];
}
// Simple test class that satisfies Comparable concept
class TestValue {
public:
int value;
TestValue(int v) : value(v) {}
int compares_to(const TestValue& other) const {
if (value > other.value) return 1;
if (value < other.value) return -1;
return 0;
}
friend ostream& operator<<(ostream& os, const TestValue& tv) {
os << tv.value;
return os;
}
};
int main() {
TestValue testArray[] = {TestValue(1), TestValue(3), TestValue(2), TestValue(3), TestValue(4), TestValue(3), TestValue(2), TestValue(1), TestValue(3)};
int size = sizeof(testArray) / sizeof(testArray[0]);
cout << "Array: ";
for(int i = 0; i < size; i++) {
cout << testArray[i] << " ";
}
cout << endl;
TestValue mostRepeated = repeatedCount(testArray, size);
cout << "Most repeated value: " << mostRepeated << endl;
return 0;
}
Task5,6
Task5
Java
/**
* Implement a function that returns the sum of the values
* in an array of integer values.
*/
public class Task9 {
public static int sumArray(int[] arr) {
int sum = 0;
for(int value : arr)
sum += value;
return sum;
}
public static void main(String[] args) {
int[] testArray = {1, 2, 3, 4, 5};
System.out.print("Array: ");
for(int num : testArray) {
System.out.print(num + " ");
}
System.out.println();
int sum = sumArray(testArray);
System.out.println("Sum of array: " + sum);
}
}
Python
"""
Implement a function that returns the sum of the values
in an array of integer values.
"""
def sum_array(arr):
#if len(arr) == 0:
# print("Array is empty")
total = 0
for value in arr:
total += value
return total
if __name__ == "__main__":
test_array = [1, 2, 3, 4, 5]
print(f"Array: {test_array}")
total = sum_array(test_array)
print(f"Sum of array: {total}")
C++
/**
* Implement a function that returns the sum of the values
* in an array of integer values.
*/
#include <iostream>
using namespace std;
int sumArray(int arr[], int size) {
int sum = 0;
for(int i = 0; i < size; i++)
sum += arr[i];
return sum;
}
int main() {
int testArray[] = {1, 2, 3, 4, 5};
int size = sizeof(testArray) / sizeof(testArray[0]);
cout << "Array: ";
for(int i = 0; i < size; i++) {
cout << testArray[i] << " ";
}
cout << endl;
int sum = sumArray(testArray, size);
cout << "Sum of array: " << sum << endl;
return 0;
}
Task6
Java
/**
* Implement a function that returns the sum of the values
* in a generic array of values with type T
*/
public class Task10 {
public static <T extends Number> double sum(T[] array) {
double result = 0;
for (T value : array) {
result += value.doubleValue();
}
return result;
}
public static void main(String[] args) {
// Test with integers
Integer[] intArray = {1, 2, 3, 4, 5};
System.out.print("Integer array: ");
for(Integer num : intArray) {
System.out.print(num + " ");
}
System.out.println();
double intSum = sum(intArray);
System.out.println("Sum of integers: " + intSum);
// Test with doubles
Double[] doubleArray = {1.5, 2.5, 3.5, 4.5, 5.5};
System.out.print("Double array: ");
for(Double num : doubleArray) {
System.out.print(num + " ");
}
System.out.println();
double doubleSum = sum(doubleArray);
System.out.println("Sum of doubles: " + doubleSum);
}
}
Python
"""
Implement a function that returns the sum of the values
in a generic array of values with type T.
"""
from typing import TypeVar, List
from numbers import Number
T = TypeVar('T', bound = Number)
def sum_array(arr: List[T]) -> T:
if not arr:
raise ValueError("Cannot sum an empty array")
total = arr[0] # Initialize with first element to maintain type T
for value in arr[1:]:
total += value
return total
if __name__ == "__main__":
# Test with integers
int_array = [1, 2, 3, 4, 5]
print(f"Integer array: {int_array}")
int_sum = sum_array(int_array)
print(f"Sum of integers: {int_sum}")
# Test with floats
float_array = [1.5, 2.5, 3.5, 4.5, 5.5]
print(f"Float array: {float_array}")
float_sum = sum_array(float_array)
print(f"Sum of floats: {float_sum}")
C++
/**
* Implement a function that returns the sum of the values
* in a generic array of values with type T
*/
#include <iostream>
using namespace std;
template<typename T>
T sumArray(T arr[], int size) {
T sum = T(); // Initialize sum to default value of type T (0 for numeric types)
for(int i = 0; i < size; i++)
sum += arr[i];
return sum;
}
int main() {
// Test with integers
int intArray[] = {1, 2, 3, 4, 5};
int intSize = sizeof(intArray) / sizeof(intArray[0]);
cout << "Integer array: ";
for(int i = 0; i < intSize; i++) {
cout << intArray[i] << " ";
}
cout << endl;
int intSum = sumArray(intArray, intSize);
cout << "Sum of integers: " << intSum << endl;
// Test with doubles
double doubleArray[] = {1.5, 2.5, 3.5, 4.5, 5.5};
int doubleSize = sizeof(doubleArray) / sizeof(doubleArray[0]);
cout << "Double array: ";
for(int i = 0; i < doubleSize; i++) {
cout << doubleArray[i] << " ";
}
cout << endl;
double doubleSum = sumArray(doubleArray, doubleSize);
cout << "Sum of doubles: " << doubleSum << endl;
return 0;
}
-
Is there any discernible difference between the implementations, i.e.: is there a language that makes
the implementation easier or more difficult?- Java: Requires explicit type constraints (
Comparable
orBiFunction
). More verbose but type-safe. - Python: Simplest implementation due to duck typing. No explicit generics needed at runtime.
- C++ : Most complex due to template syntax, operator overloading, and concepts. Offers compile-time safety but requires more boilerplate.
Ease Ranking: Python > Java > C++
- Java: Requires explicit type constraints (
-
Is there any feature or lack of a feature in one or more of the three languages that prevents to
implement a proper solution?- Java: No operator overloading forces use of
Comparable
or functional interfaces. - Python: No compile-time type checks (runtime errors possible).
- C++ : Concepts require C++20. Custom types need explicit operator/function definitions.
All languages support a proper solution, but with different trade-offs.
- Java: No operator overloading forces use of
-
Is there any requirement on the values to be able to implement the solution? Could you write this
requirement as a checkable restriction? How? You don’t need to implement it, just provide description
on howCore Requirement: Values must be comparable - they need to support some form of ordering relationship.
How to express this as checkable restrictions:
Python (Runtime checking):
from typing import Protocol class Comparable(Protocol): def __gt__(self, other) -> bool: ... def maxOfArray(arr: list[Comparable]) -> Comparable: # Implementation remains the same
Java (Compile-time bounded generics):
// Already shown in your code: public static <T extends Comparable<? super T>> T maximum_c(T[] values) // Or with custom comparator: public static <T> T maximum_f(T[] values, BiFunction<T, T, T> fmax)
C++ (Compile-time concepts - most expressive):
// Already shown in your code: template<typename T> concept Comparable = requires(T a, T b) { {a.comparesTo(b)} -> std::same_as<int>; }; // Or using standard operators: template<typename T> concept Orderable = requires(T a, T b) { {a > b} -> std::same_as<bool>; };
Task 6 What is the purpose of using Concepts in C++?
Concepts in C++ serve several crucial purposes:
-
Compile-time Constraints: Ensure template parameters meet specific requirements before instantiation
-
Better Error Messages: Instead of cryptic template errors, you get clear constraint violations
-
Self-documenting Code: Concepts make template requirements explicit in the interface
-
Overload Resolution: Enable function overloading based on concept satisfaction
-
Template Specialization: Allow different implementations for different concept-satisfying types
Task 7 Can we pass functions as arguments in any of the languages we saw (Java, C++, Python)? Is there any
meaning difference between how this is done in the three languages
Yes, all three languages support passing functions as arguments, but with different mechanisms:
Java - Function Objects/Lambda Expressions:
BiFunction<Integer, Integer, Integer> int_max = (a, b) -> a > b ? a : b;
maximum_f(values, int_max);
- Uses functional interfaces (
BiFunction
) - Lambda expressions or method references
- Type-safe with generics
C++ - Function Pointers/Templates:
template<typename T>
using t_max = T (*)(T, T); // Function pointer type alias
int max(int a, int b) { return a > b ? a : b; }
maximum_f<int>(size, values, max);
- Function pointers (shown)
- Function objects/functors
- Lambda expressions (C++11+)
- Templates can accept any callable
Python - First-class Functions:
def custom_max(a, b):
return a if a > b else b
def maxOfArray(arr, compare_func=lambda a, b: a if a > b else b):
# Could be implemented to use compare_func
- Functions are first-class objects
- Can pass functions directly
- Lambda expressions
- Most flexible - any callable object works
C++ constructor Example
#include <iostream>
#include <cassert>
class OptionalInt {
private:
int * value = nullptr;
public:
OptionalInt() {
this->value = nullptr;
}
OptionalInt(int value) {
this->value = new int(value);
}
OptionalInt(const OptionalInt& other) {
if (this->is_present()) {
delete this->value;
}
if (other.is_present()) {
this->value = new int(other.get_value());
} else {
this->value = nullptr;
}
}
bool is_present() const {
return this->value != nullptr;
}
int get_value() const{
assert(is_present());
return *this->value;
}
~OptionalInt() {
if (is_present()) {
delete value;
}
}
friend std::ostream& operator<<(std::ostream& out, OptionalInt& optional);
};
std::ostream& operator<<(std::ostream& out, OptionalInt& optional) {
//optional cannot be null, the & in here is stating that the argument is passed as a reference
if (optional.is_present()) {
out << "Optional(" << optional.get_value() << ")";
} else {
out << "Empty";
}
return out;
}
static OptionalInt maximum(int size, int values[]);
static int parse_argument(const char * const arg);
int main(const int argc, const char ** const argv) {
int values_size = argc - 1;
int values[values_size];
for (int i = 1; i < argc; i++) {
values[i - 1] = parse_argument(argv[i]);
}
OptionalInt maximum_value = maximum(values_size, values);
std::cout << "The maximum value found was: " << maximum_value << std::endl;
return 0;
}
static OptionalInt maximum(int size, int values[]) {
if (size == 0) {
OptionalInt empty = OptionalInt();
return empty;
}
int max = values[0];
for (int i = 1; i < size; i++) {
int current = values[i];
if (current > max) {
max = current;
}
}
return OptionalInt(max);
}
static int parse_argument(const char * const arg) {
int num;
try {
std::string int_str = std::string(arg);
num = std::stoi(int_str);
} catch (const std::invalid_argument& e) {
std::cerr << "Invalid argument: " << e.what() << std::endl;
} catch (const std::out_of_range& e) {
std::cerr << "Out of range: " << e.what() << std::endl;
}
return num;
}
Exercise 13
Java
package Task1_2;
import java.util.ArrayList;
public class Dictionary<K, V> {
private ArrayList<Entry<K, V>> entries;
private static class Entry<K, V> {
final K key;
V value;
Entry(K key, V value) {
this.key = key;
this.value = value;
}
}
public Dictionary() {
this.entries = new ArrayList<>();
}
/**
* Puts a key-value pair into the dictionary.
* If the key already exists, updates the value.
* @param key the key
* @param value the value
*/
public void put(K key, V value) {
for (Entry<K, V> entry : entries) {
if (entry.key.equals(key)) {
entry.value = value;
return;
}
}
entries.add(new Entry<>(key, value));
}
/**
* Gets the value associated with the given key.
* Returns Optional.empty() if the key doesn't exist.
* @param key the key to look up
* @return Optional containing the value if found, empty otherwise
*/
public Optional<V> get(K key) {
for (Entry<K, V> entry : entries) {
if (entry.key.equals(key)) {
return Optional.of(entry.value);
}
}
return Optional.empty();
}
/**
* Removes the key-value pair for the given key.
* @param key the key to remove
* @return true if the key was found and removed, false otherwise
*/
public boolean remove(K key) {
for (int i = 0; i < entries.size(); i++) {
if (entries.get(i).key.equals(key)) {
entries.remove(i);
return true;
}
}
return false;
}
/**
* Checks if the dictionary contains the given key.
* @param key the key to check
* @return true if the key exists, false otherwise
*/
public boolean containsKey(K key) {
for (Entry<K, V> entry : entries) {
if (entry.key.equals(key)) {
return true;
}
}
return false;
}
/**
* Returns the number of key-value pairs in the dictionary.
* @return the size of the dictionary
*/
public int size() {
return entries.size();
}
/**
* Checks if the dictionary is empty.
* @return true if the dictionary is empty, false otherwise
*/
public boolean isEmpty() {
return entries.isEmpty();
}
/**
* Removes all key-value pairs from the dictionary.
*/
public void clear() {
entries.clear();
}
/**
* Returns a string representation of the dictionary.
* @return string representation showing all key-value pairs
*/
@Override
public String toString() {
if (isEmpty()) {
return "{}";
}
StringBuilder sb = new StringBuilder();
sb.append("{");
for (int i = 0; i < entries.size(); i++) {
Entry<K, V> entry = entries.get(i);
sb.append(entry.key).append("=").append(entry.value);
if (i < entries.size() - 1) {
sb.append(", ");
}
}
sb.append("}");
return sb.toString();
}
}
Python
"""
Implement in both Python and C++ a Dictionary class that maps values of
a generic type K to a generic type V.
Consider the case where a user wants to get the value for a key
that doesn’t exist
"""
from typing import TypeVar, Generic, Dict, Optional, List, Tuple
K = TypeVar('K')
V = TypeVar('V')
class Dictionary(Generic[K, V]):
"""
A generic dictionary mapping keys of type K to values of type V.
"""
def __init__(self) -> None:
self._data: Dict[K, V] = {}
def add(self, key: K, value: V) -> None:
"""
Add a key-value pair. Raises KeyError if key already exists.
"""
if key in self._data:
raise KeyError(f"Key {key} already exists.")
self._data[key] = value
def get(self, key: K, default: Optional[V] = None) -> V:
"""
Get the value for key. If key does not exist:
- If default provided, return default
- Otherwise, raise KeyError
"""
if key in self._data:
return self._data[key]
if default is not None:
return default
raise KeyError(f"Key {key} does not exist.")
def remove(self, key: K) -> None:
"""
Remove the key. Raises KeyError if key does not exist.
"""
if key not in self._data:
raise KeyError(f"Key {key} does not exist.")
del self._data[key]
def contains(self, key: K) -> bool:
"""
Check if the key exists in dictionary.
"""
return key in self._data
def keys(self) -> List[K]:
return list(self._data.keys())
def values(self) -> List[V]:
return list(self._data.values())
def items(self) -> List[Tuple[K, V]]:
return list(self._data.items())
def __len__(self) -> int:
return len(self._data)
def __getitem__(self, key: K) -> V:
return self.get(key)
def __setitem__(self, key: K, value: V) -> None:
self._data[key] = value
C++
/*
Implement in both Python and C++ a Dictionary class that maps values of
a generic type K to a generic type V.
Consider the case where a user wants to get the value for a key
that doesn’t exist
*/
#include <map>
#include <iostream>
#include <string>
template<typename K, typename V>
class Dictionary {
private:
std::map<K, V> data;
public:
// Insert or update a key-value pair
void put(const K& key, const V& value) {
data[key] = value;
}
// Get value by key, returns pointer to value or nullptr if not found
// This is safe way to handle non-existing keys
V* get(const K& key) {
auto it = data.find(key);
if (it != data.end()) {
return &(it->second);
}
return nullptr; // Key doesn't exist
}
// Get value with a default value if key doesn't exist
V getValue(const K& key, const V& defaultValue) const {
auto it = data.find(key);
if (it != data.end()) {
return it->second;
}
return defaultValue;
}
// Check if key exists in the dictionary
bool contains(const K& key) const {
return data.find(key) != data.end();
}
// Remove a key-value pair
bool remove(const K& key) {
return data.erase(key) > 0;
}
// Get the number of key-value pairs
size_t size() const {
return data.size();
}
// Check if dictionary is empty
bool empty() const {
return data.empty();
}
// Print all key-value pairs (for demonstration)
void printAll() const {
std::cout << "Dictionary contents:\n";
for (const auto& pair : data) {
std::cout << "Key: " << pair.first << ", Value: " << pair.second << "\n";
}
}
};
// Example usage and demonstration
int main() {
// Create a dictionary that maps strings to integers
Dictionary<std::string, int> ages;
// Add some data
ages.put("Alice", 25);
ages.put("Bob", 30);
ages.put("Charlie", 35);
std::cout << "=== Dictionary Demo ===\n";
ages.printAll();
std::cout << "\n";
// Safe way to get values - using pointer
std::cout << "Getting values safely with pointers:\n";
int* aliceAge = ages.get("Alice");
if (aliceAge != nullptr) {
std::cout << "Alice's age: " << *aliceAge << "\n";
}
int* davidAge = ages.get("David"); // This key doesn't exist
if (davidAge != nullptr) {
std::cout << "David's age: " << *davidAge << "\n";
} else {
std::cout << "David not found in dictionary\n";
}
// Using default values
std::cout << "\nUsing default values:\n";
int bobAge = ages.getValue("Bob", 0);
int eveAge = ages.getValue("Eve", 0); // Doesn't exist, will return 0
std::cout << "Bob's age: " << bobAge << "\n";
std::cout << "Eve's age (default): " << eveAge << "\n";
// Check if keys exist
std::cout << "\nChecking if keys exist:\n";
std::cout << "Contains Alice? " << (ages.contains("Alice") ? "Yes" : "No") << "\n";
std::cout << "Contains Frank? " << (ages.contains("Frank") ? "Yes" : "No") << "\n";
// Dictionary with different types
std::cout << "\n=== Different Types Demo ===\n";
Dictionary<int, std::string> names;
names.put(1, "One");
names.put(2, "Two");
names.put(3, "Three");
std::string* name = names.get(2);
if (name != nullptr) {
std::cout << "Number 2 is: " << *name << "\n";
}
std::string unknownName = names.getValue(5, "Unknown");
std::cout << "Number 5 is: " << unknownName << "\n";
return 0;
}