From 1e2d852c4648a4ed0972f73a0905b072e985ec93 Mon Sep 17 00:00:00 2001 From: Alexey Date: Wed, 21 Jan 2026 14:21:35 +0200 Subject: [PATCH] complete exercises --- .../bobocode/intro/ExerciseIntroduction.java | 9 +- .../main/java/com/bobocode/basics/Box.java | 10 +- .../java/com/bobocode/basics/BoxDemoApp.java | 10 +- .../com/bobocode/basics/CrazyGenerics.java | 92 +++++++---- .../basics/HeterogeneousMaxHolder.java | 31 +++- .../java/com/bobocode/basics/Exercise.java | 14 ++ .../basics/HelloAnnotationsExercise.java | 4 +- .../src/main/java/com/bobobode/cs/Node.java | 20 ++- .../src/main/java/com/bobobode/cs/Nodes.java | 47 +++++- .../java/com/bobocode/cs/LinkedStack.java | 62 ++++++- .../java/com/bobocode/cs/LinkedQueue.java | 46 +++++- .../main/java/com/bobocode/cs/LinkedList.java | 140 ++++++++++++++-- .../main/java/com/bobocode/cs/ArrayList.java | 76 +++++++-- .../cs/RecursiveBinarySearchTree.java | 108 +++++++++++- .../main/java/com/bobocode/cs/HashTable.java | 156 ++++++++++++++++-- .../java/com/bobocode/se/FileReaders.java | 20 ++- .../main/java/com/bobocode/se/FileStats.java | 91 ++++++++-- .../main/java/com/bobocode/se/CrazyRegex.java | 51 +++--- .../bobocode/se/RandomFieldComparator.java | 38 ++++- .../java/com/bobocode/oop/data/FlightDao.java | 17 +- .../com/bobocode/oop/data/IFlightDao.java | 10 ++ .../oop/factory/FlightServiceFactory.java | 2 +- .../bobocode/oop/service/FlightService.java | 17 +- .../main/java/com/bobocode/fp/Functions.java | 5 + .../java/com/bobocode/fp/SumOfSquares.java | 8 +- .../java/com/bobocode/fp/CrazyLambdas.java | 70 +++++--- .../java/com/bobocode/fp/CrazyStreams.java | 59 +++++-- .../java/com/bobocode/fp/CrazyOptionals.java | 48 ++++-- .../java/com/bobocode/fp/PrimeNumbers.java | 19 ++- 29 files changed, 1053 insertions(+), 227 deletions(-) create mode 100644 1-0-java-basics/1-5-0-hello-annotations/src/main/java/com/bobocode/basics/Exercise.java create mode 100644 4-0-object-oriented-programming/4-3-1-flight-search/src/main/java/com/bobocode/oop/data/IFlightDao.java diff --git a/0-0-intro/src/main/java/com/bobocode/intro/ExerciseIntroduction.java b/0-0-intro/src/main/java/com/bobocode/intro/ExerciseIntroduction.java index 35d925636..181b9990e 100644 --- a/0-0-intro/src/main/java/com/bobocode/intro/ExerciseIntroduction.java +++ b/0-0-intro/src/main/java/com/bobocode/intro/ExerciseIntroduction.java @@ -1,6 +1,7 @@ package com.bobocode.intro; -import com.bobocode.util.ExerciseNotCompletedException; +import java.nio.charset.StandardCharsets; +import java.util.Base64; /** * Welcome! This is an introduction exercise that will show you a simple example of Bobocode exercises. @@ -23,8 +24,7 @@ public class ExerciseIntroduction { * @return "The key to efficient learning is practice!" */ public String getWelcomeMessage() { - // todo: implement a method and return a message according to javadoc - throw new ExerciseNotCompletedException(); + return "The key to efficient learning is practice!"; } /** @@ -39,7 +39,6 @@ public String getWelcomeMessage() { * @return encoded message */ public String encodeMessage(String message) { - // todo: switch to branch "completed" in order to see how it should be implemented - throw new ExerciseNotCompletedException(); + return Base64.getEncoder().encodeToString(message.getBytes(StandardCharsets.UTF_8)); } } diff --git a/1-0-java-basics/1-3-0-hello-generics/src/main/java/com/bobocode/basics/Box.java b/1-0-java-basics/1-3-0-hello-generics/src/main/java/com/bobocode/basics/Box.java index 5a2d860ee..180603a28 100644 --- a/1-0-java-basics/1-3-0-hello-generics/src/main/java/com/bobocode/basics/Box.java +++ b/1-0-java-basics/1-3-0-hello-generics/src/main/java/com/bobocode/basics/Box.java @@ -7,18 +7,18 @@ *

* todo: refactor this class so it uses generic type "T" and run {@link com.bobocode.basics.BoxTest} to verify it */ -public class Box { - private Object value; +public class Box { + private T value; - public Box(Object value) { + public Box(T value) { this.value = value; } - public Object getValue() { + public T getValue() { return value; } - public void setValue(Object value) { + public void setValue(T value) { this.value = value; } } diff --git a/1-0-java-basics/1-3-0-hello-generics/src/main/java/com/bobocode/basics/BoxDemoApp.java b/1-0-java-basics/1-3-0-hello-generics/src/main/java/com/bobocode/basics/BoxDemoApp.java index bc12174ee..9893166a8 100644 --- a/1-0-java-basics/1-3-0-hello-generics/src/main/java/com/bobocode/basics/BoxDemoApp.java +++ b/1-0-java-basics/1-3-0-hello-generics/src/main/java/com/bobocode/basics/BoxDemoApp.java @@ -9,13 +9,13 @@ */ public class BoxDemoApp { public static void main(String[] args) { - Box intBox = new Box(123); - Box intBox2 = new Box(321); - System.out.println((int) intBox.getValue() + (int) intBox2.getValue()); + var intBox = new Box<>(123); + var intBox2 = new Box<>(321); + System.out.println(intBox.getValue() + intBox2.getValue()); intBox.setValue(222); - intBox.setValue("abc"); // this should not be allowed +// intBox.setValue("abc"); // this should not be allowed // the following code will compile, but will throw runtime exception - System.out.println((int) intBox.getValue() + (int) intBox2.getValue()); + System.out.println(intBox.getValue() + intBox2.getValue()); } } diff --git a/1-0-java-basics/1-3-1-crazy-generics/src/main/java/com/bobocode/basics/CrazyGenerics.java b/1-0-java-basics/1-3-1-crazy-generics/src/main/java/com/bobocode/basics/CrazyGenerics.java index 751d5899f..d41d0a3af 100644 --- a/1-0-java-basics/1-3-1-crazy-generics/src/main/java/com/bobocode/basics/CrazyGenerics.java +++ b/1-0-java-basics/1-3-1-crazy-generics/src/main/java/com/bobocode/basics/CrazyGenerics.java @@ -5,10 +5,10 @@ import lombok.Data; import java.io.Serializable; -import java.util.Collection; -import java.util.Comparator; -import java.util.List; -import java.util.Objects; +import java.util.*; +import java.util.function.Predicate; +import java.util.stream.Collectors; +import java.util.stream.Stream; /** * {@link CrazyGenerics} is an exercise class. It consists of classes, interfaces and methods that should be updated @@ -33,8 +33,8 @@ public class CrazyGenerics { * @param – value type */ @Data - public static class Sourced { // todo: refactor class to introduce type parameter and make value generic - private Object value; + public static class Sourced { // todo: refactor class to introduce type parameter and make value generic + private T value; private String source; } @@ -45,11 +45,11 @@ public static class Sourced { // todo: refactor class to introduce type paramete * @param – actual, min and max type */ @Data - public static class Limited { + public static class Limited { // todo: refactor class to introduce type param bounded by number and make fields generic numbers - private final Object actual; - private final Object min; - private final Object max; + private final T actual; + private final T min; + private final T max; } /** @@ -59,8 +59,8 @@ public static class Limited { * @param – source object type * @param - converted result type */ - public interface Converter { // todo: introduce type parameters - // todo: add convert method + public interface Converter { // todo: introduce type parameters + R convert(T value); } /** @@ -70,10 +70,10 @@ public interface Converter { // todo: introduce type parameters * * @param – value type */ - public static class MaxHolder { // todo: refactor class to make it generic - private Object max; + public static class MaxHolder> { // todo: refactor class to make it generic + private T max; - public MaxHolder(Object max) { + public MaxHolder(T max) { this.max = max; } @@ -82,11 +82,11 @@ public MaxHolder(Object max) { * * @param val a new value */ - public void put(Object val) { - throw new ExerciseNotCompletedException(); // todo: update parameter and implement the method + public void put(T val) { + this.max = max.compareTo(val) < 0 ? val : max; } - public Object getMax() { + public T getMax() { return max; } } @@ -97,8 +97,8 @@ public Object getMax() { * * @param – the type of objects that can be processed */ - interface StrictProcessor { // todo: make it generic - void process(Object obj); + interface StrictProcessor & Serializable> { // todo: make it generic + void process(T obj); } /** @@ -108,10 +108,10 @@ interface StrictProcessor { // todo: make it generic * @param – a type of the entity that should be a subclass of {@link BaseEntity} * @param – a type of any collection */ - interface CollectionRepository { // todo: update interface according to the javadoc - void save(Object entity); + interface CollectionRepository> { // todo: update interface according to the javadoc + void save(T entity); - Collection getEntityCollection(); + C getEntityCollection(); } /** @@ -120,7 +120,7 @@ interface CollectionRepository { // todo: update interface according to the java * * @param – a type of the entity that should be a subclass of {@link BaseEntity} */ - interface ListRepository { // todo: update interface according to the javadoc + interface ListRepository extends CollectionRepository> { // todo: update interface according to the javadoc } /** @@ -133,7 +133,11 @@ interface ListRepository { // todo: update interface according to the javadoc * * @param a type of collection elements */ - interface ComparableCollection { // todo: refactor it to make generic and provide a default impl of compareTo + interface ComparableCollection extends Collection, Comparable>{ + @Override + default int compareTo(Collection o) { + return Integer.compare(this.size(), o.size()); + } } /** @@ -147,7 +151,7 @@ static class CollectionUtil { * * @param list */ - public static void print(List list) { + public static void print(List list) { // todo: refactor it so the list of any type can be printed, not only integers list.forEach(element -> System.out.println(" – " + element)); } @@ -160,8 +164,8 @@ public static void print(List list) { * @param entities provided collection of entities * @return true if at least one of the elements has null id */ - public static boolean hasNewEntities(Collection entities) { - throw new ExerciseNotCompletedException(); // todo: refactor parameter and implement method + public static boolean hasNewEntities(Collection entities) { + return entities.stream().anyMatch(entity -> entity.getUuid() == null); } /** @@ -173,8 +177,8 @@ public static boolean hasNewEntities(Collection entities) { * @param validationPredicate criteria for validation * @return true if all entities fit validation criteria */ - public static boolean isValidCollection() { - throw new ExerciseNotCompletedException(); // todo: add method parameters and implement the logic + public static boolean isValidCollection(Collection entities, Predicate validationPredicate) { + return entities.stream().allMatch(validationPredicate); } /** @@ -187,8 +191,8 @@ public static boolean isValidCollection() { * @param entity type * @return true if entities list contains target entity more than once */ - public static boolean hasDuplicates() { - throw new ExerciseNotCompletedException(); // todo: update method signature and implement it + public static boolean hasDuplicates(Collection entities, T targetEntity) { + return entities.stream().filter(entity -> entity.getUuid().equals(targetEntity.getUuid())).count() > 1; } /** @@ -201,7 +205,18 @@ public static boolean hasDuplicates() { * @return optional max value */ // todo: create a method and implement its logic manually without using util method from JDK - + public static Optional findMax(Iterable elements, Comparator comparator) { + T max = null; + Iterator iterator = elements.iterator(); + while (iterator.hasNext()) { + var element = iterator.next(); + if (max == null) { max = element; } + if (comparator.compare(element, max) > 0) { + max = element; + }; + } + return Optional.ofNullable(max); + } /** * findMostRecentlyCreatedEntity is a generic util method that accepts a collection of entities and returns the * one that is the most recently created. If collection is empty, @@ -215,7 +230,10 @@ public static boolean hasDuplicates() { * @return an entity from the given collection that has the max createdOn value */ // todo: create a method according to JavaDoc and implement it using previous method - + public static T findMostRecentlyCreatedEntity(Collection entities){ + if (entities == null || entities.isEmpty()) throw new NoSuchElementException(); + return (T) findMax(entities.stream().collect(Collectors.toUnmodifiableSet()), CREATED_ON_COMPARATOR).get(); + } /** * An util method that allows to swap two elements of any list. It changes the list so the element with the index * i will be located on index j, and the element with index j, will be located on the index i. @@ -228,7 +246,11 @@ public static boolean hasDuplicates() { public static void swap(List elements, int i, int j) { Objects.checkIndex(i, elements.size()); Objects.checkIndex(j, elements.size()); - throw new ExerciseNotCompletedException(); // todo: complete method implementation + var elementI = elements.get(i); + var elementJ = elements.get(j); + final List l = elements; + l.set(i, elementJ); + l.set(j, elementI); } } diff --git a/1-0-java-basics/1-3-2-heterogeneous-max-holder/src/main/java/com/bobocode/basics/HeterogeneousMaxHolder.java b/1-0-java-basics/1-3-2-heterogeneous-max-holder/src/main/java/com/bobocode/basics/HeterogeneousMaxHolder.java index 9ef839910..b300f7924 100644 --- a/1-0-java-basics/1-3-2-heterogeneous-max-holder/src/main/java/com/bobocode/basics/HeterogeneousMaxHolder.java +++ b/1-0-java-basics/1-3-2-heterogeneous-max-holder/src/main/java/com/bobocode/basics/HeterogeneousMaxHolder.java @@ -1,5 +1,7 @@ package com.bobocode.basics; +import java.util.Comparator; +import java.util.HashMap; import java.util.Map; /** @@ -16,6 +18,8 @@ */ public class HeterogeneousMaxHolder { + private final Map, Object> map = new HashMap<>(); + /** * A method put stores a provided value by its type, if the value is greater than the current maximum. In other words, the logic * of this method makes sure that only max value is stored and everything else is ignored. @@ -31,7 +35,17 @@ public class HeterogeneousMaxHolder { * @return a smaller value among the provided value and the current maximum */ // todo: implement a method according to javadoc - + public > T put(Class key, T value) { + if (!map.containsKey(key)) { + map.put(key, value); + return null; + } + var storedValue = (T) map.get(key); + if (value.compareTo(storedValue) > 0) { + map.put(key, value); + return storedValue; + } else return value; + } /** * An overloaded method put implements the same logic using a custom comparator. A given comparator is wrapped with * a null-safe comparator, considering null smaller than any non-null object. @@ -45,7 +59,17 @@ public class HeterogeneousMaxHolder { * @return a smaller value among the provided value and the current maximum */ // todo: implement a method according to javadoc - + public T put(Class key, T value, Comparator comparator) { + if (!map.containsKey(key)) { + map.put(key, value); + return null; + } + var storedValue = (T) map.get(key); + if (comparator.compare(value, storedValue) > 0) { + map.put(key, value); + return storedValue; + } else return value; + } /** * A method getMax returns a max value by the given type. If no value is stored by this type, then it returns null. * @@ -54,4 +78,7 @@ public class HeterogeneousMaxHolder { * @return current max value or null */ // todo: implement a method according to javadoc + public T getMax(Class key) { + return (T) map.get(key); + } } diff --git a/1-0-java-basics/1-5-0-hello-annotations/src/main/java/com/bobocode/basics/Exercise.java b/1-0-java-basics/1-5-0-hello-annotations/src/main/java/com/bobocode/basics/Exercise.java new file mode 100644 index 000000000..7c3a45e78 --- /dev/null +++ b/1-0-java-basics/1-5-0-hello-annotations/src/main/java/com/bobocode/basics/Exercise.java @@ -0,0 +1,14 @@ +package com.bobocode.basics; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface Exercise { + String name() default "hello-annotation-basic"; + String value() default ""; + Level complexityLevel() default Level.BASIC; +} diff --git a/1-0-java-basics/1-5-0-hello-annotations/src/main/java/com/bobocode/basics/HelloAnnotationsExercise.java b/1-0-java-basics/1-5-0-hello-annotations/src/main/java/com/bobocode/basics/HelloAnnotationsExercise.java index 4dc8c4b22..0f8fff9a8 100644 --- a/1-0-java-basics/1-5-0-hello-annotations/src/main/java/com/bobocode/basics/HelloAnnotationsExercise.java +++ b/1-0-java-basics/1-5-0-hello-annotations/src/main/java/com/bobocode/basics/HelloAnnotationsExercise.java @@ -13,5 +13,7 @@ * * @author Taras Boychuk */ -public class HelloAnnotationsExercise { // todo: mark class with the annotation according to the javadoc +@Exercise(value = "hello-annotation-basic", complexityLevel = Level.BASIC) +public class HelloAnnotationsExercise { + } diff --git a/2-0-data-structures-and-algorithms/2-2-1-node/src/main/java/com/bobobode/cs/Node.java b/2-0-data-structures-and-algorithms/2-2-1-node/src/main/java/com/bobobode/cs/Node.java index b01a4acfb..68a942eeb 100644 --- a/2-0-data-structures-and-algorithms/2-2-1-node/src/main/java/com/bobobode/cs/Node.java +++ b/2-0-data-structures-and-algorithms/2-2-1-node/src/main/java/com/bobobode/cs/Node.java @@ -1,5 +1,8 @@ package com.bobobode.cs; +import lombok.Getter; +import lombok.Setter; + /** * Class {@link Node} is a very simple data structure that consists of an element itself and the reference to the next * node. An element can have any value since it's a generic. A reference to the next node allows to link {@link Node} @@ -9,5 +12,20 @@ * @author Taras Boychuk */ public class Node { - // todo: + @Getter + private T value; + + @Getter + @Setter + private Node next; + + public Node(T value) { + this.value = value; + } + + public Node(T value, Node next) { + this.value = value; + this.next = next; + } + } diff --git a/2-0-data-structures-and-algorithms/2-2-1-node/src/main/java/com/bobobode/cs/Nodes.java b/2-0-data-structures-and-algorithms/2-2-1-node/src/main/java/com/bobobode/cs/Nodes.java index 5321aa53a..63867492d 100644 --- a/2-0-data-structures-and-algorithms/2-2-1-node/src/main/java/com/bobobode/cs/Nodes.java +++ b/2-0-data-structures-and-algorithms/2-2-1-node/src/main/java/com/bobobode/cs/Nodes.java @@ -1,6 +1,7 @@ package com.bobobode.cs; -import com.bobocode.util.ExerciseNotCompletedException; +import java.util.ArrayList; +import java.util.List; /** * A class that consists of static methods only and provides util methods for {@link Node}. @@ -11,6 +12,7 @@ * @author Taras Boychuk */ public class Nodes { + private Nodes() { } @@ -22,7 +24,7 @@ private Nodes() { * @return a new instance of {@link Node} */ public static Node create(T element) { - throw new ExerciseNotCompletedException(); // todo: + return new Node<>(element); } /** @@ -33,7 +35,8 @@ public static Node create(T element) { * @param a genetic type */ public static void link(Node first, Node second) { - throw new ExerciseNotCompletedException(); // todo: + if (first == null || second == null) { return; } + first.setNext(second); } /** @@ -46,7 +49,7 @@ public static void link(Node first, Node second) { * @return a reference to a first node created based on firstElement */ public static Node pairOf(T firstElement, T secondElement) { - throw new ExerciseNotCompletedException(); // todo: + return new Node<>(firstElement, new Node<>(secondElement)); } /** @@ -60,7 +63,11 @@ public static Node pairOf(T firstElement, T secondElement) { * @return a reference to the first node */ public static Node closedPairOf(T firstElement, T secondElement) { - throw new ExerciseNotCompletedException(); // todo: + var firstNode = new Node<>(firstElement); + var secondNode = new Node<>(secondElement); + firstNode.setNext(secondNode); + secondNode.setNext(firstNode); + return firstNode; } /** @@ -72,7 +79,20 @@ public static Node closedPairOf(T firstElement, T secondElement) { * @return a reference to the first element of the chain */ public static Node chainOf(T... elements) { - throw new ExerciseNotCompletedException(); // todo: + List elementsList = List.of(elements); + List nodes = new ArrayList<>(elementsList.size()); + for (int i = 0; i <= elementsList.size() - 1; i++) { + if (i == elementsList.size() - 1) { + nodes.add(new Node<>(elementsList.get(i))); + } else { + var firstNode = i != 0 ? nodes.getLast() : new Node<>(elementsList.get(i)); + var nextNode = new Node<>(elementsList.get(i + 1)); + firstNode.setNext(nextNode); + nodes.add(firstNode); + nodes.add(nextNode); + } + } + return nodes.getFirst(); } /** @@ -85,6 +105,19 @@ public static Node chainOf(T... elements) { * @return a reference to the first element of the chain */ public static Node circleOf(T... elements) { - throw new ExerciseNotCompletedException(); // todo: + List elementsList = List.of(elements); + List nodes = new ArrayList<>(elementsList.size()); + for (int i = 0; i <= elementsList.size() - 1; i++) { + if (i == elementsList.size() - 1) { + nodes.getLast().setNext(nodes.getFirst()); + } else { + var firstNode = i != 0 ? nodes.getLast() : new Node<>(elementsList.get(i)); + var nextNode = new Node<>(elementsList.get(i + 1)); + firstNode.setNext(nextNode); + nodes.add(firstNode); + nodes.add(nextNode); + } + } + return nodes.getFirst(); } } diff --git a/2-0-data-structures-and-algorithms/2-2-2-stack/src/main/java/com/bobocode/cs/LinkedStack.java b/2-0-data-structures-and-algorithms/2-2-2-stack/src/main/java/com/bobocode/cs/LinkedStack.java index 05b0c724d..29a17d2fb 100644 --- a/2-0-data-structures-and-algorithms/2-2-2-stack/src/main/java/com/bobocode/cs/LinkedStack.java +++ b/2-0-data-structures-and-algorithms/2-2-2-stack/src/main/java/com/bobocode/cs/LinkedStack.java @@ -1,7 +1,13 @@ package com.bobocode.cs; import com.bobocode.cs.exception.EmptyStackException; -import com.bobocode.util.ExerciseNotCompletedException; +import lombok.Getter; +import lombok.Setter; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.stream.Stream; /** * {@link LinkedStack} is a stack implementation that is based on singly linked generic nodes. @@ -16,6 +22,12 @@ */ public class LinkedStack implements Stack { + private Node head; + + private int size; + + public LinkedStack() {} + /** * This method creates a stack of provided elements * @@ -24,7 +36,9 @@ public class LinkedStack implements Stack { * @return a new stack of elements that were passed as method parameters */ public static LinkedStack of(T... elements) { - throw new ExerciseNotCompletedException(); // todo: implement this method + LinkedStack linkedStack = new LinkedStack<>(); + Stream.of(elements).forEach(linkedStack::push); + return linkedStack; } /** @@ -35,7 +49,13 @@ public static LinkedStack of(T... elements) { */ @Override public void push(T element) { - throw new ExerciseNotCompletedException(); // todo: implement this method + Objects.requireNonNull(element); + Node newNode = Node.valueOf(element); + if (head != null) { + newNode.next = head; + } + head = newNode; + size++; } /** @@ -47,7 +67,14 @@ public void push(T element) { */ @Override public T pop() { - throw new ExerciseNotCompletedException(); // todo: implement this method + if (head != null) { + size--; + var element = head.getValue(); + this.head = head.next; + return element; + } else { + throw new EmptyStackException(); + } } /** @@ -57,7 +84,7 @@ public T pop() { */ @Override public int size() { - throw new ExerciseNotCompletedException(); // todo: implement this method + return size; } /** @@ -67,7 +94,28 @@ public int size() { */ @Override public boolean isEmpty() { - throw new ExerciseNotCompletedException(); // todo: implement this method; - } + return head == null; } + + private static class Node { + @Getter + private T value; + + @Getter + @Setter + private Node next; + + private Node(T value) { + this.value = value; + } + + private Node(T value, Node next) { + this.value = value; + this.next = next; + } + + private static Node valueOf(T element) { + return new Node<>(element); + } + } } diff --git a/2-0-data-structures-and-algorithms/2-2-3-linked-queue/src/main/java/com/bobocode/cs/LinkedQueue.java b/2-0-data-structures-and-algorithms/2-2-3-linked-queue/src/main/java/com/bobocode/cs/LinkedQueue.java index 7b4a79667..5e8a8b1ea 100644 --- a/2-0-data-structures-and-algorithms/2-2-3-linked-queue/src/main/java/com/bobocode/cs/LinkedQueue.java +++ b/2-0-data-structures-and-algorithms/2-2-3-linked-queue/src/main/java/com/bobocode/cs/LinkedQueue.java @@ -16,13 +16,26 @@ */ public class LinkedQueue implements Queue { + private Node head; + + private Node tail; + + private int size; + /** * Adds an element to the end of the queue. * * @param element the element to add */ public void add(T element) { - throw new ExerciseNotCompletedException(); // todo: implement this method + Node newNode = Node.valueOf(element); + if (head == null) { + head = tail = newNode; + } else { + tail.next = newNode; + tail = newNode; + } + size++; } /** @@ -31,7 +44,17 @@ public void add(T element) { * @return an element that was retrieved from the head or null if queue is empty */ public T poll() { - throw new ExerciseNotCompletedException(); // todo: implement this method + if (head != null) { + T element = head.element; + head = head.next; + if (head == null) { + tail = null; + } + size--; + return element; + } else { + return null; + } } /** @@ -40,7 +63,7 @@ public T poll() { * @return an integer value that is a size of queue */ public int size() { - throw new ExerciseNotCompletedException(); // todo: implement this method + return size; } /** @@ -49,6 +72,21 @@ public int size() { * @return {@code true} if the queue is empty, returns {@code false} if it's not */ public boolean isEmpty() { - throw new ExerciseNotCompletedException(); // todo: implement this method + return head == null; + } + + private static final class Node { + + private final T element; + + private Node next; + + private static Node valueOf(T element) { + return new Node<>(element); + } + + private Node(T element) { + this.element = element; + } } } diff --git a/2-0-data-structures-and-algorithms/2-2-4-linked-list/src/main/java/com/bobocode/cs/LinkedList.java b/2-0-data-structures-and-algorithms/2-2-4-linked-list/src/main/java/com/bobocode/cs/LinkedList.java index 502fefbdf..0982304bc 100644 --- a/2-0-data-structures-and-algorithms/2-2-4-linked-list/src/main/java/com/bobocode/cs/LinkedList.java +++ b/2-0-data-structures-and-algorithms/2-2-4-linked-list/src/main/java/com/bobocode/cs/LinkedList.java @@ -3,6 +3,10 @@ import com.bobocode.util.ExerciseNotCompletedException; +import java.util.NoSuchElementException; +import java.util.Objects; +import java.util.stream.Stream; + /** * {@link LinkedList} is a list implementation that is based on singly linked generic nodes. A node is implemented as * inner static class {@link Node}. @@ -16,6 +20,12 @@ */ public class LinkedList implements List { + private Node first; + + private Node last; + + private int size; + /** * This method creates a list of provided elements * @@ -24,7 +34,9 @@ public class LinkedList implements List { * @return a new list of elements the were passed as method parameters */ public static LinkedList of(T... elements) { - throw new ExerciseNotCompletedException(); // todo: implement this method + LinkedList linkedList = new LinkedList<>(); + Stream.of(elements).forEach(linkedList::add); + return linkedList; } /** @@ -34,7 +46,14 @@ public static LinkedList of(T... elements) { */ @Override public void add(T element) { - throw new ExerciseNotCompletedException(); // todo: implement this method + Node newNode = new Node<>(element); + if (size == 0) { + first = last = newNode; + } else { + last.next = newNode; + last = newNode; + } + size++; } /** @@ -46,7 +65,51 @@ public void add(T element) { */ @Override public void add(int index, T element) { - throw new ExerciseNotCompletedException(); // todo: implement this method + Node newNode = Node.valueOf(element); + if (index == 0) { + addAsHead(newNode); + } else if (index == size) { + addAsTail(newNode); + } else { + add(index, newNode); + } + size++; + } + + private void addAsHead(Node newNode) { + newNode.next = first; + first = newNode; + if (first.next == null) { + last = first; + } + } + + private void addAsTail(Node newNode) { + last.next = newNode; + last = newNode; + } + + private void add(int index, Node newNode) { + Node node = findNodeByIndex(index - 1); + newNode.next = node.next; + node.next = newNode; + } + + private Node findNodeByIndex(int index) { + Objects.checkIndex(index, size); + if (index == size - 1) { + return last; + } else { + return nodeAt(index); + } + } + + private Node nodeAt(int index) { + Node currentNode = first; + for (int i = 0; i < index; i++) { + currentNode = currentNode.next; + } + return currentNode; } /** @@ -58,7 +121,8 @@ public void add(int index, T element) { */ @Override public void set(int index, T element) { - throw new ExerciseNotCompletedException(); // todo: implement this method + Node node = findNodeByIndex(index); + node.value = element; } /** @@ -70,7 +134,8 @@ public void set(int index, T element) { */ @Override public T get(int index) { - throw new ExerciseNotCompletedException(); // todo: implement this method + Node node = findNodeByIndex(index); + return node.value; } /** @@ -81,7 +146,8 @@ public T get(int index) { */ @Override public T getFirst() { - throw new ExerciseNotCompletedException(); // todo: implement this method + checkElementsExist(); + return first.value; } /** @@ -92,7 +158,14 @@ public T getFirst() { */ @Override public T getLast() { - throw new ExerciseNotCompletedException(); // todo: implement this method + checkElementsExist(); + return last.value; + } + + private void checkElementsExist() { + if (first == null) { + throw new NoSuchElementException(); + } } /** @@ -104,7 +177,27 @@ public T getLast() { */ @Override public T remove(int index) { - throw new ExerciseNotCompletedException(); // todo: implement this method + T deletedElement; + if (index == 0 && !isEmpty()) { + deletedElement = first.value; + removeHead(); + } else { + Node previousNode = findNodeByIndex(index - 1); + deletedElement = previousNode.next.value; + previousNode.next = previousNode.next.next; + if (index == size - 1) { + last = previousNode; + } + } + size--; + return deletedElement; + } + + private void removeHead() { + first = first.next; + if (first == null) { + last = null; + } } @@ -115,7 +208,14 @@ public T remove(int index) { */ @Override public boolean contains(T element) { - throw new ExerciseNotCompletedException(); // todo: implement this method + Node currentNode = first; + while (currentNode != null) { + if (currentNode.value.equals(element)) { + return true; + } + currentNode = currentNode.next; + } + return false; } /** @@ -125,7 +225,7 @@ public boolean contains(T element) { */ @Override public boolean isEmpty() { - throw new ExerciseNotCompletedException(); // todo: implement this method + return first == null; } /** @@ -135,7 +235,7 @@ public boolean isEmpty() { */ @Override public int size() { - throw new ExerciseNotCompletedException(); // todo: implement this method + return size; } /** @@ -143,6 +243,22 @@ public int size() { */ @Override public void clear() { - throw new ExerciseNotCompletedException(); // todo: implement this method + first = last = null; + size = 0; + } + + private static class Node { + + private T value; + + private Node next; + + private Node(T value) { + this.value = value; + } + + private static Node valueOf(T value) { + return new Node<>(value); + } } } diff --git a/2-0-data-structures-and-algorithms/2-2-5-array-list/src/main/java/com/bobocode/cs/ArrayList.java b/2-0-data-structures-and-algorithms/2-2-5-array-list/src/main/java/com/bobocode/cs/ArrayList.java index 384ca81e5..8e03f5bdb 100644 --- a/2-0-data-structures-and-algorithms/2-2-5-array-list/src/main/java/com/bobocode/cs/ArrayList.java +++ b/2-0-data-structures-and-algorithms/2-2-5-array-list/src/main/java/com/bobocode/cs/ArrayList.java @@ -1,6 +1,8 @@ package com.bobocode.cs; -import com.bobocode.util.ExerciseNotCompletedException; +import java.util.Arrays; +import java.util.NoSuchElementException; +import java.util.Objects; /** * {@link ArrayList} is an implementation of {@link List} interface. This resizable data structure @@ -13,6 +15,12 @@ */ public class ArrayList implements List { + private static final int DEFAULT_CAPACITY = 5; + + private Object[] elementData; + + private int size; + /** * This constructor creates an instance of {@link ArrayList} with a specific capacity of an array inside. * @@ -20,7 +28,10 @@ public class ArrayList implements List { * @throws IllegalArgumentException – if the specified initial capacity is negative or 0. */ public ArrayList(int initCapacity) { - throw new ExerciseNotCompletedException(); // todo: implement this method + if (initCapacity <= 0) { + throw new IllegalArgumentException(); + } + elementData = new Object[initCapacity]; } /** @@ -28,7 +39,7 @@ public ArrayList(int initCapacity) { * A default size of inner array is 5; */ public ArrayList() { - throw new ExerciseNotCompletedException(); // todo: implement this method + this(DEFAULT_CAPACITY); } /** @@ -38,7 +49,10 @@ public ArrayList() { * @return new instance */ public static List of(T... elements) { - throw new ExerciseNotCompletedException(); // todo: implement this method + ArrayList list = new ArrayList<>(elements.length); + list.elementData = Arrays.copyOf(elements, elements.length); + list.size = elements.length; + return list; } /** @@ -48,7 +62,15 @@ public static List of(T... elements) { */ @Override public void add(T element) { - throw new ExerciseNotCompletedException(); // todo: implement this method + increaseDataArrayIfFull(); + elementData[size] = element; + size++; + } + + private void increaseDataArrayIfFull() { + if (elementData.length == size) { + elementData = Arrays.copyOf(elementData, size * 2); + } } /** @@ -59,7 +81,10 @@ public void add(T element) { */ @Override public void add(int index, T element) { - throw new ExerciseNotCompletedException(); // todo: implement this method + increaseDataArrayIfFull(); + System.arraycopy(elementData, index, elementData, index + 1, size - index); + elementData[index] = element; + size++; } /** @@ -71,7 +96,8 @@ public void add(int index, T element) { */ @Override public T get(int index) { - throw new ExerciseNotCompletedException(); // todo: implement this method + Objects.checkIndex(index, size); + return (T) elementData[index]; } /** @@ -82,7 +108,10 @@ public T get(int index) { */ @Override public T getFirst() { - throw new ExerciseNotCompletedException(); // todo: implement this method + if (isEmpty()) { + throw new NoSuchElementException(); + } + return (T) elementData[0]; } /** @@ -93,7 +122,10 @@ public T getFirst() { */ @Override public T getLast() { - throw new ExerciseNotCompletedException(); // todo: implement this method + if (isEmpty()) { + throw new NoSuchElementException(); + } + return (T) elementData[size - 1]; } /** @@ -105,7 +137,8 @@ public T getLast() { */ @Override public void set(int index, T element) { - throw new ExerciseNotCompletedException(); // todo: implement this method + Objects.checkIndex(index, size); + elementData[index] = element; } /** @@ -117,7 +150,14 @@ public void set(int index, T element) { */ @Override public T remove(int index) { - throw new ExerciseNotCompletedException(); // todo: implement this method + Objects.checkIndex(index, size); + T deletedElement = (T) elementData[index]; + if (index < size - 1) { + System.arraycopy(elementData, index + 1, elementData, index, size - index - 1); + } + elementData[size - 1] = null; + size--; + return deletedElement; } /** @@ -128,7 +168,12 @@ public T remove(int index) { */ @Override public boolean contains(T element) { - throw new ExerciseNotCompletedException(); // todo: implement this method + for (int i = 0; i < size; i++) { + if (elementData[i].equals(element)) { + return true; + } + } + return false; } /** @@ -138,7 +183,7 @@ public boolean contains(T element) { */ @Override public boolean isEmpty() { - throw new ExerciseNotCompletedException(); // todo: implement this method + return size == 0; } /** @@ -146,7 +191,7 @@ public boolean isEmpty() { */ @Override public int size() { - throw new ExerciseNotCompletedException(); // todo: implement this method + return size; } /** @@ -154,6 +199,7 @@ public int size() { */ @Override public void clear() { - throw new ExerciseNotCompletedException(); // todo: implement this method + elementData = new Object[DEFAULT_CAPACITY]; + size = 0; } } diff --git a/2-0-data-structures-and-algorithms/2-2-6-binary-search-tree/src/main/java/com/bobocode/cs/RecursiveBinarySearchTree.java b/2-0-data-structures-and-algorithms/2-2-6-binary-search-tree/src/main/java/com/bobocode/cs/RecursiveBinarySearchTree.java index a4e394b0b..2ac02f8a7 100644 --- a/2-0-data-structures-and-algorithms/2-2-6-binary-search-tree/src/main/java/com/bobocode/cs/RecursiveBinarySearchTree.java +++ b/2-0-data-structures-and-algorithms/2-2-6-binary-search-tree/src/main/java/com/bobocode/cs/RecursiveBinarySearchTree.java @@ -2,7 +2,9 @@ import com.bobocode.util.ExerciseNotCompletedException; +import java.util.Objects; import java.util.function.Consumer; +import java.util.stream.Stream; /** * {@link RecursiveBinarySearchTree} is an implementation of a {@link BinarySearchTree} that is based on a linked nodes @@ -18,32 +20,126 @@ */ public class RecursiveBinarySearchTree> implements BinarySearchTree { + private static class Node { + + T element; + + Node left; + + Node right; + + private Node(T element) { + this.element = element; + } + + private static Node valueOf(T element) { + return new Node<>(element); + } + } + + private Node root; + + private int size = 0; + public static > RecursiveBinarySearchTree of(T... elements) { - throw new ExerciseNotCompletedException(); + RecursiveBinarySearchTree bst = new RecursiveBinarySearchTree<>(); + Stream.of(elements).forEach(bst::insert); + return bst; } @Override public boolean insert(T element) { - throw new ExerciseNotCompletedException(); + Objects.requireNonNull(element); + boolean isInserted = insertElement(element); + if (isInserted) { + size++; + } + return isInserted; + } + + boolean insertElement(T element) { + if (root == null) { + root = Node.valueOf(element); + return true; + } else { + return insertIntoSubTree(root, element); + } } @Override public boolean contains(T element) { - throw new ExerciseNotCompletedException(); + Objects.requireNonNull(element); + return findChildNodeByElement(root, element) != null; + } + + private boolean insertIntoSubTree(Node subTreeRoot, T element) { + if (subTreeRoot.element.compareTo(element) > 0) { + return insertIntoLeftSubtree(subTreeRoot, element); + } else if (subTreeRoot.element.compareTo(element) < 0) { + return insertIntoRightSubtree(subTreeRoot, element); + } else { + return false; + } + } + + private boolean insertIntoLeftSubtree(Node node, T element) { + if (node.left != null) { + return insertIntoSubTree(node.left, element); + } else { + node.left = Node.valueOf(element); + return true; + } + } + + private boolean insertIntoRightSubtree(Node node, T element) { + if (node.right != null) { + return insertIntoSubTree(node.right, element); + } else { + node.right = Node.valueOf(element); + return true; + } } @Override public int size() { - throw new ExerciseNotCompletedException(); + return size; + } + + private Node findChildNodeByElement(Node node, T element) { + if (node == null) { + return null; + } else if (node.element.compareTo(element) > 0) { + return findChildNodeByElement(node.left, element); + } else if (node.element.compareTo(element) < 0) { + return findChildNodeByElement(node.right, element); + } else { + return node; + } } @Override public int depth() { - throw new ExerciseNotCompletedException(); + return root != null ? depth(root) - 1 : 0; + } + + private int depth(Node node) { + if (node == null) { + return 0; + } else { + return 1 + Math.max(depth(node.left), depth(node.right)); + } } @Override public void inOrderTraversal(Consumer consumer) { - throw new ExerciseNotCompletedException(); + inOrderTraversal(root, consumer); + } + + private void inOrderTraversal(Node node, Consumer consumer) { + if (node != null) { + inOrderTraversal(node.left, consumer); + consumer.accept(node.element); + inOrderTraversal(node.right, consumer); + } } } diff --git a/2-0-data-structures-and-algorithms/2-2-9-hash-table/src/main/java/com/bobocode/cs/HashTable.java b/2-0-data-structures-and-algorithms/2-2-9-hash-table/src/main/java/com/bobocode/cs/HashTable.java index ade9cea4d..154b0bad9 100644 --- a/2-0-data-structures-and-algorithms/2-2-9-hash-table/src/main/java/com/bobocode/cs/HashTable.java +++ b/2-0-data-structures-and-algorithms/2-2-9-hash-table/src/main/java/com/bobocode/cs/HashTable.java @@ -1,6 +1,9 @@ package com.bobocode.cs; import com.bobocode.util.ExerciseNotCompletedException; +import lombok.ToString; + +import static java.util.Objects.requireNonNull; /** * {@link HashTable} is a simple Hashtable-based implementation of {@link Map} interface with some additional methods. @@ -28,6 +31,23 @@ */ public class HashTable implements Map { + private static final int DEFAULT_CAPACITY = 8; + + private static final float RESIZE_THRESHOLD = 1.0f; + + private Node[] table; + + private int size; + + @SuppressWarnings("unchecked") + public HashTable(int initialCapacity) { + verifyCapacity(initialCapacity); + this.table = new Node[initialCapacity]; + } + + public HashTable() { + this(DEFAULT_CAPACITY); + } /** * This method is a critical part of the hast table. The main idea is that having a key, you can calculate its index * in the array using the hash code. Since the computation is done in constant time (O(1)), it's faster than @@ -43,7 +63,8 @@ public class HashTable implements Map { * @return array index of the given key */ public static int calculateIndex(Object key, int tableCapacity) { - throw new ExerciseNotCompletedException(); // todo: + var hash = key.hashCode() ^ (key.hashCode() >> 16); + return hash & (tableCapacity - 1); } /** @@ -59,7 +80,40 @@ public static int calculateIndex(Object key, int tableCapacity) { */ @Override public V put(K key, V value) { - throw new ExerciseNotCompletedException(); // todo: + resizeIfNeeded(); + return putOnTable(table, key, value); + } + + private void resizeIfNeeded() { + if (size / (float) table.length > RESIZE_THRESHOLD) { + resizeTable(2 * table.length); + } + } + + private V putOnTable(Node[] table, K key, V value) { + var newNode = new Node<>(requireNonNull(key), requireNonNull(value)); + var index = calculateIndex(key, table.length); + if (table[index] == null) { // add new head key + table[index] = newNode; + } else { + var current = table[index]; + while (current.next != null) { // iterate linked list to new key + if (current.key.equals(key)) { + var prevValue = current.value; + current.value = value; + return prevValue; + } + current = current.next; + } + if (current.key.equals(key)) { + var prevValue = current.value; + current.value = value; + return prevValue; + } + current.next = newNode; // attach new key to the end of the list + } + size++; + return null; } /** @@ -71,7 +125,15 @@ public V put(K key, V value) { */ @Override public V get(K key) { - throw new ExerciseNotCompletedException(); // todo: + var index = calculateIndex(requireNonNull(key), table.length); + var current = table[index]; + while (current != null) { + if (current.key.equals(key)) { + return current.value; + } + current = current.next; + } + return null; } /** @@ -82,7 +144,7 @@ public V get(K key) { */ @Override public boolean containsKey(K key) { - throw new ExerciseNotCompletedException(); // todo: + return get(key) != null; } /** @@ -93,7 +155,16 @@ public boolean containsKey(K key) { */ @Override public boolean containsValue(V value) { - throw new ExerciseNotCompletedException(); // todo: + for (var head : table) { + var current = head; + while (current != null) { + if (current.value.equals(value)) { + return true; + } + current = current.next; + } + } + return false; } /** @@ -103,7 +174,7 @@ public boolean containsValue(V value) { */ @Override public int size() { - throw new ExerciseNotCompletedException(); // todo: + return size; } /** @@ -113,7 +184,7 @@ public int size() { */ @Override public boolean isEmpty() { - throw new ExerciseNotCompletedException(); // todo: + return size == 0; } /** @@ -124,7 +195,26 @@ public boolean isEmpty() { */ @Override public V remove(K key) { - throw new ExerciseNotCompletedException(); // todo: + var index = calculateIndex(requireNonNull(key), table.length); + var current = table[index]; + if (current != null) { + if (current.key.equals(key)) { + var value = current.value; + table[index] = current.next; + size--; + return value; + } + while (current.next != null) { + if (current.next.key.equals(key)) { + var value = current.next.value; + current.next = current.next.next; + size--; + return value; + } + current = current.next; + } + } + return null; } /** @@ -150,7 +240,22 @@ public V remove(K key) { */ @Override public String toString() { - throw new ExerciseNotCompletedException(); // todo: + var stringBuilder = new StringBuilder(); + var n = table.length; + for (int i = 0; i < n; i++) { // iterate array + stringBuilder.append(i).append(": "); + var current = table[i]; + if (current != null) { + while (current.next != null) { // iterate each linked list + stringBuilder.append(current.key).append("=").append(current.value).append(" -> "); + current = current.next; + } + stringBuilder.append(current.key).append("=").append(current.value).append("\n"); + } else { + stringBuilder.append("\n"); + } + } + return stringBuilder.toString(); } /** @@ -167,6 +272,37 @@ public String toString() { * @param newCapacity a size of the new underlying array */ public void resizeTable(int newCapacity) { - throw new ExerciseNotCompletedException(); // todo: + verifyCapacity(newCapacity); + @SuppressWarnings("unchecked") Node[] newTable = new Node[newCapacity]; + size = 0; + for (var head : table) { + var current = head; + while (current != null) { + putOnTable(newTable, current.key, current.value); + current = current.next; + } + } + table = newTable; + } + + private void verifyCapacity(int capacity) { + if (capacity <= 0) { + throw new IllegalArgumentException("Capacity (table array size) must be positive"); + } + } + + @ToString(exclude = "next") + public static class Node { + + T key; + + V value; + + Node next; + + public Node(T key, V value) { + this.key = key; + this.value = value; + } } } diff --git a/3-0-java-core/3-6-1-file-reader/src/main/java/com/bobocode/se/FileReaders.java b/3-0-java-core/3-6-1-file-reader/src/main/java/com/bobocode/se/FileReaders.java index 6370a3638..f518af31f 100644 --- a/3-0-java-core/3-6-1-file-reader/src/main/java/com/bobocode/se/FileReaders.java +++ b/3-0-java-core/3-6-1-file-reader/src/main/java/com/bobocode/se/FileReaders.java @@ -2,6 +2,17 @@ import com.bobocode.util.ExerciseNotCompletedException; +import java.io.IOException; +import java.net.URISyntaxException; +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Objects; +import java.util.stream.Stream; + +import static java.util.stream.Collectors.joining; + /** * {@link FileReaders} provides an API that allow to read whole file into a {@link String} by file name. */ @@ -14,6 +25,13 @@ public class FileReaders { * @return string that holds whole file content */ public static String readWholeFile(String fileName) { - throw new ExerciseNotCompletedException(); //todo + try { + var fileUrl = FileReaders.class.getClassLoader().getResource(fileName); + var filePath = Paths.get(fileUrl.toURI()); + return Files.readString(filePath); + } catch (URISyntaxException | IOException e) { + throw new RuntimeException(e); + } + } } diff --git a/3-0-java-core/3-6-2-file-stats/src/main/java/com/bobocode/se/FileStats.java b/3-0-java-core/3-6-2-file-stats/src/main/java/com/bobocode/se/FileStats.java index 56b4aa596..ea4e5b9fc 100644 --- a/3-0-java-core/3-6-2-file-stats/src/main/java/com/bobocode/se/FileStats.java +++ b/3-0-java-core/3-6-2-file-stats/src/main/java/com/bobocode/se/FileStats.java @@ -1,12 +1,88 @@ package com.bobocode.se; import com.bobocode.util.ExerciseNotCompletedException; +import lombok.Getter; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Comparator; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Stream; + +import static java.util.function.Function.identity; +import static java.util.stream.Collectors.counting; +import static java.util.stream.Collectors.groupingBy; /** * {@link FileStats} provides an API that allow to get character statistic based on text file. All whitespace characters * are ignored. */ public class FileStats { + + private final Map characterCountMap; + /** + * -- GETTER -- + * Returns a character that appeared most often in the text. + * + * @return the most frequently appeared character + */ + @Getter + private final char mostPopularCharacter; + + private FileStats(String fileName) { + Path filePath = getFilePath(fileName); + characterCountMap = computeCharacterMap(filePath); + mostPopularCharacter = findMostPopularCharacter(characterCountMap); + } + + private Path getFilePath(String fileName) { + Objects.requireNonNull(fileName); + URL fileUrl = getFileUrl(fileName); + try { + return Paths.get(fileUrl.toURI()); + } catch (URISyntaxException e) { + throw new FileStatsException("Wrong file path", e); + } + } + + private Map computeCharacterMap(Path filePath) { + try (var lines = Files.lines(filePath)) { + return collectCharactersToCountMap(lines); + } catch (IOException e) { + throw new FileStatsException("Cannot read the file", e); + } + } + + private Map collectCharactersToCountMap(Stream linesStream) { + return linesStream + .flatMapToInt(String::chars) + .filter(a -> a != 32) // filter whitespace + .mapToObj(c -> (char) c) + .collect(groupingBy(identity(), counting())); + } + + + private URL getFileUrl(String fileName) { + URL fileUrl = getClass().getClassLoader().getResource(fileName); + if (fileUrl == null) { + throw new FileStatsException("Wrong file path"); + } + return fileUrl; + } + + private char findMostPopularCharacter(Map characterCountMap) { + return characterCountMap.entrySet() + .stream() + .max(Map.Entry.comparingByValue()) + .get() + .getKey(); + } + /** * Creates a new immutable {@link FileStats} objects using data from text file received as a parameter. * @@ -14,7 +90,7 @@ public class FileStats { * @return new FileStats object created from text file */ public static FileStats from(String fileName) { - throw new ExerciseNotCompletedException(); //todo + return new FileStats(fileName); } /** @@ -24,16 +100,7 @@ public static FileStats from(String fileName) { * @return a number that shows how many times this character appeared in a text file */ public int getCharCount(char character) { - throw new ExerciseNotCompletedException(); //todo - } - - /** - * Returns a character that appeared most often in the text. - * - * @return the most frequently appeared character - */ - public char getMostPopularCharacter() { - throw new ExerciseNotCompletedException(); //todo + return characterCountMap.get(character).intValue(); } /** @@ -43,6 +110,6 @@ public char getMostPopularCharacter() { * @return {@code true} if this character has appeared in the text, and {@code false} otherwise */ public boolean containsCharacter(char character) { - throw new ExerciseNotCompletedException(); //todo + return characterCountMap.containsKey(character); } } diff --git a/3-0-java-core/3-6-3-crazy-regex/src/main/java/com/bobocode/se/CrazyRegex.java b/3-0-java-core/3-6-3-crazy-regex/src/main/java/com/bobocode/se/CrazyRegex.java index e213d3f26..80652ac29 100644 --- a/3-0-java-core/3-6-3-crazy-regex/src/main/java/com/bobocode/se/CrazyRegex.java +++ b/3-0-java-core/3-6-3-crazy-regex/src/main/java/com/bobocode/se/CrazyRegex.java @@ -21,7 +21,7 @@ public class CrazyRegex { * @return a pattern that looks for the word "Curiosity" */ public Pattern findSpecificWord() { - throw new ExerciseNotCompletedException(); + return Pattern.compile("Curiosity"); } /** @@ -30,7 +30,7 @@ public Pattern findSpecificWord() { * @return a pattern that looks for the first word in text */ public Pattern findFirstWord() { - throw new ExerciseNotCompletedException(); + return Pattern.compile("^\\w+"); } /** @@ -39,7 +39,7 @@ public Pattern findFirstWord() { * @return a pattern that looks for the last word in text */ public Pattern findLastWord() { - throw new ExerciseNotCompletedException(); + return Pattern.compile("\\w+$"); } /** @@ -50,7 +50,7 @@ public Pattern findLastWord() { * @return a pattern that looks for numbers */ public Pattern findAllNumbers() { - throw new ExerciseNotCompletedException(); + return Pattern.compile("\\d+"); } /** @@ -59,7 +59,7 @@ public Pattern findAllNumbers() { * @return a pattern that looks for dates */ public Pattern findDates() { - throw new ExerciseNotCompletedException(); + return Pattern.compile("\\d{4}-\\d{2}-\\d{2}"); } /** @@ -69,7 +69,7 @@ public Pattern findDates() { * @return a pattern that looks for different variations of word "color" */ public Pattern findDifferentSpellingsOfColor() { - throw new ExerciseNotCompletedException(); + return Pattern.compile("colou?rs?"); } /** @@ -80,7 +80,7 @@ public Pattern findDifferentSpellingsOfColor() { * @return a pattern that looks for zip codes */ public Pattern findZipCodes() { - throw new ExerciseNotCompletedException(); + return Pattern.compile("\\s\\d{5}\\s"); } /** @@ -90,7 +90,7 @@ public Pattern findZipCodes() { * @return a pattern that looks for different variations of word "link" */ public Pattern findDifferentSpellingsOfLink() { - throw new ExerciseNotCompletedException(); + return Pattern.compile("l[yi (]nk"); } /** @@ -100,7 +100,7 @@ public Pattern findDifferentSpellingsOfLink() { * @return a pattern that looks for phone numbers */ public Pattern findSimplePhoneNumber() { - throw new ExerciseNotCompletedException(); + return Pattern.compile("\\d\\d\\d-\\d\\d\\d-\\d\\d\\d\\d"); } /** @@ -111,7 +111,7 @@ public Pattern findSimplePhoneNumber() { * @return a pattern that looks for numbers with length 3 and digits from 0 to 5 in the middle */ public Pattern findNumbersFromZeroToFiveWithLengthThree() { - throw new ExerciseNotCompletedException(); + return Pattern.compile("[0-5]{3}"); } /** @@ -120,7 +120,7 @@ public Pattern findNumbersFromZeroToFiveWithLengthThree() { * @return a pattern that looks for the words that have length 5 */ public Pattern findAllWordsWithFiveLength() { - throw new ExerciseNotCompletedException(); + return Pattern.compile("\\b[A-Za-z]{5}\\b"); } /** @@ -131,7 +131,7 @@ public Pattern findAllWordsWithFiveLength() { * @return a pattern that looks for words and numbers that not shorter 2 and not longer 3 */ public Pattern findAllLettersAndDigitsWithLengthThree() { - throw new ExerciseNotCompletedException(); + return Pattern.compile("\\b\\w{2,3}\\b"); } /** @@ -140,7 +140,7 @@ public Pattern findAllLettersAndDigitsWithLengthThree() { * @return a pattern that looks for the words that begin with capital letter */ public Pattern findAllWordsWhichBeginWithCapitalLetter() { - throw new ExerciseNotCompletedException(); + return Pattern.compile("\\b[A-Z][a-z]*\\b"); } /** @@ -150,7 +150,7 @@ public Pattern findAllWordsWhichBeginWithCapitalLetter() { * @return a pattern that looks for the abbreviations above */ public Pattern findAbbreviation() { - throw new ExerciseNotCompletedException(); + return Pattern.compile("A[KLRZ]|C[AOT]|P[RAD]"); } /** @@ -159,7 +159,7 @@ public Pattern findAbbreviation() { * @return a pattern that looks for all open braces */ public Pattern findAllOpenBraces() { - throw new ExerciseNotCompletedException(); + return Pattern.compile("(\\{+)"); } /** @@ -168,7 +168,7 @@ public Pattern findAllOpenBraces() { * @return a pattern that looks for everything inside [] */ public Pattern findOnlyResources() { - throw new ExerciseNotCompletedException(); + return Pattern.compile("(?<=\\[).+?(?=\\])"); } /** @@ -177,7 +177,7 @@ public Pattern findOnlyResources() { * @return a pattern that looks for all https links in note.txt */ public Pattern findOnlyLinksInNote() { - throw new ExerciseNotCompletedException(); + return Pattern.compile("https://((www.)?+[\\w]+(.))com"); } /** @@ -186,7 +186,7 @@ public Pattern findOnlyLinksInNote() { * @return a pattern that looks for all http links in nasa.json */ public Pattern findOnlyLinksInJson() { - throw new ExerciseNotCompletedException(); + return Pattern.compile("http://(.*)JPG"); } /** @@ -195,7 +195,7 @@ public Pattern findOnlyLinksInJson() { * @return a pattern that looks for all .com, .net and .edu emails */ public Pattern findAllEmails() { - throw new ExerciseNotCompletedException(); + return Pattern.compile("[\\w.]+@[\\w]+\\.(net|com|edu)"); } /** @@ -207,7 +207,7 @@ public Pattern findAllEmails() { * @return a pattern that looks for phone numbers patterns above */ public Pattern findAllPatternsForPhoneNumbers() { - throw new ExerciseNotCompletedException(); + return Pattern.compile("\\(?\\d{3}[-.)]\\d{3}[-.]\\d{4}"); } /** @@ -216,7 +216,7 @@ public Pattern findAllPatternsForPhoneNumbers() { * @return a pattern that looks for duplicates */ public Pattern findOnlyDuplicates() { - throw new ExerciseNotCompletedException(); + return Pattern.compile("\\b(\\w+)\\s\\1\\b"); } /** @@ -227,7 +227,8 @@ public Pattern findOnlyDuplicates() { * @return String where all names recorded as last name first name */ public String replaceFirstAndLastNames(String names) { - throw new ExerciseNotCompletedException(); + var matcher = Pattern.compile("(\\w+),\\s+(\\w+)").matcher(names); + return matcher.replaceAll("$2 $1"); } /** @@ -238,7 +239,8 @@ public String replaceFirstAndLastNames(String names) { * @return String where in all phone numbers last 7 digits replaced to X */ public String replaceLastSevenDigitsOfPhoneNumberToX(String phones) { - throw new ExerciseNotCompletedException(); + var matcher = Pattern.compile("\\(?(\\d{3})[-.)]\\d{3}[-.]\\d{4}").matcher(phones); + return matcher.replaceAll("$1-XXX-XXXX"); } /** @@ -250,6 +252,7 @@ public String replaceLastSevenDigitsOfPhoneNumberToX(String phones) { * @return String where all resources embraced in href */ public String insertLinksAndResourcesIntoHref(String links) { - throw new ExerciseNotCompletedException(); + var matcher = Pattern.compile("\\[(.*?)]\\((http.*?)\\)").matcher(links); + return matcher.replaceAll("$1"); } } diff --git a/3-0-java-core/3-6-4-random-field-comparator/src/main/java/com/bobocode/se/RandomFieldComparator.java b/3-0-java-core/3-6-4-random-field-comparator/src/main/java/com/bobocode/se/RandomFieldComparator.java index 760989875..0e68b210f 100644 --- a/3-0-java-core/3-6-4-random-field-comparator/src/main/java/com/bobocode/se/RandomFieldComparator.java +++ b/3-0-java-core/3-6-4-random-field-comparator/src/main/java/com/bobocode/se/RandomFieldComparator.java @@ -1,8 +1,14 @@ package com.bobocode.se; import com.bobocode.util.ExerciseNotCompletedException; +import lombok.SneakyThrows; + +import java.lang.reflect.Field; +import java.util.Arrays; import java.util.Comparator; +import static java.util.Objects.requireNonNull; + /** * A generic comparator that is comparing a random field of the given class. The field is either primitive or * {@link Comparable}. It is chosen during comparator instance creation and is used for all comparisons. @@ -18,8 +24,19 @@ */ public class RandomFieldComparator implements Comparator { + private final Class targetType; + + private final Field fieldToCompare; + public RandomFieldComparator(Class targetType) { - throw new ExerciseNotCompletedException(); // todo: implement this constructor; + this.targetType = requireNonNull(targetType); + this.fieldToCompare = chooseFieldToCompare(targetType); + } + + private Field chooseFieldToCompare(Class targetType) { + return Arrays.stream(targetType.getDeclaredFields()) + .filter(f -> Comparable.class.isAssignableFrom(f.getType()) || f.getType().isPrimitive()) + .findAny().orElseThrow(() -> new IllegalArgumentException("There are no fields available to compare")); } /** @@ -34,14 +51,26 @@ public RandomFieldComparator(Class targetType) { */ @Override public int compare(T o1, T o2) { - throw new ExerciseNotCompletedException(); // todo: implement this method; + requireNonNull(o1); + requireNonNull(o2); + return compareFieldValues(o1, o2); + } + + @SneakyThrows + @SuppressWarnings("unchecked") + private > int compareFieldValues(T o1, T o2) { + fieldToCompare.setAccessible(true); + var value1 = (U) fieldToCompare.get(o1); + var value2 = (U) fieldToCompare.get(o2); + Comparator comparator = Comparator.nullsLast(Comparator.naturalOrder()); + return comparator.compare(value1, value2); } /** * Returns the name of the randomly-chosen comparing field. */ public String getComparingFieldName() { - throw new ExerciseNotCompletedException(); // todo: implement this method; + return fieldToCompare.getName(); } /** @@ -52,6 +81,7 @@ public String getComparingFieldName() { */ @Override public String toString() { - throw new ExerciseNotCompletedException(); // todo: implement this method; + return String.format("Random field comparator of class '%s' is comparing '%s'", targetType.getSimpleName(), + getComparingFieldName()); } } diff --git a/4-0-object-oriented-programming/4-3-1-flight-search/src/main/java/com/bobocode/oop/data/FlightDao.java b/4-0-object-oriented-programming/4-3-1-flight-search/src/main/java/com/bobocode/oop/data/FlightDao.java index 3e58c3b33..f4696c9ec 100644 --- a/4-0-object-oriented-programming/4-3-1-flight-search/src/main/java/com/bobocode/oop/data/FlightDao.java +++ b/4-0-object-oriented-programming/4-3-1-flight-search/src/main/java/com/bobocode/oop/data/FlightDao.java @@ -1,7 +1,6 @@ package com.bobocode.oop.data; -import com.bobocode.util.ExerciseNotCompletedException; - +import java.util.Collections; import java.util.HashSet; import java.util.Set; @@ -12,8 +11,9 @@ * todo: 1. Implement a method {@link FlightDao#register(String)} that store new flight number into the set * todo: 2. Implement a method {@link FlightDao#findAll()} that returns a set of all flight numbers */ -public class FlightDao { - private Set flights = new HashSet<>(); +public class FlightDao implements IFlightDao { + + private final Set flights = new HashSet<>(); /** * Stores a new flight number @@ -21,8 +21,12 @@ public class FlightDao { * @param flightNumber a flight number to store * @return {@code true} if a flight number was stored, {@code false} otherwise */ + @Override public boolean register(String flightNumber) { - throw new ExerciseNotCompletedException();// todo: implement this method + if (!flights.contains(flightNumber)) { + this.flights.add(flightNumber); + return true; + } else return false; } /** @@ -30,8 +34,9 @@ public boolean register(String flightNumber) { * * @return a set of flight numbers */ + @Override public Set findAll() { - throw new ExerciseNotCompletedException();// todo: implement this method + return Collections.unmodifiableSet(flights); } } diff --git a/4-0-object-oriented-programming/4-3-1-flight-search/src/main/java/com/bobocode/oop/data/IFlightDao.java b/4-0-object-oriented-programming/4-3-1-flight-search/src/main/java/com/bobocode/oop/data/IFlightDao.java new file mode 100644 index 000000000..6691d2d3e --- /dev/null +++ b/4-0-object-oriented-programming/4-3-1-flight-search/src/main/java/com/bobocode/oop/data/IFlightDao.java @@ -0,0 +1,10 @@ +package com.bobocode.oop.data; + +import java.util.Set; + +public interface IFlightDao { + + boolean register(String flightNumber); + + Set findAll(); +} diff --git a/4-0-object-oriented-programming/4-3-1-flight-search/src/main/java/com/bobocode/oop/factory/FlightServiceFactory.java b/4-0-object-oriented-programming/4-3-1-flight-search/src/main/java/com/bobocode/oop/factory/FlightServiceFactory.java index 8cd2ed673..92b7d9331 100644 --- a/4-0-object-oriented-programming/4-3-1-flight-search/src/main/java/com/bobocode/oop/factory/FlightServiceFactory.java +++ b/4-0-object-oriented-programming/4-3-1-flight-search/src/main/java/com/bobocode/oop/factory/FlightServiceFactory.java @@ -16,6 +16,6 @@ public class FlightServiceFactory { * @return FlightService */ public FlightService creteFlightService() { - throw new ExerciseNotCompletedException(); + return new FlightService(); } } diff --git a/4-0-object-oriented-programming/4-3-1-flight-search/src/main/java/com/bobocode/oop/service/FlightService.java b/4-0-object-oriented-programming/4-3-1-flight-search/src/main/java/com/bobocode/oop/service/FlightService.java index b31cd8f07..1cd9f5d49 100644 --- a/4-0-object-oriented-programming/4-3-1-flight-search/src/main/java/com/bobocode/oop/service/FlightService.java +++ b/4-0-object-oriented-programming/4-3-1-flight-search/src/main/java/com/bobocode/oop/service/FlightService.java @@ -1,8 +1,11 @@ package com.bobocode.oop.service; +import com.bobocode.oop.data.FlightDao; +import com.bobocode.oop.data.IFlightDao; import com.bobocode.util.ExerciseNotCompletedException; import java.util.List; +import java.util.Set; /** * {@link FlightService} provides an API that allows to manage flight numbers @@ -12,6 +15,16 @@ */ public class FlightService { + private final IFlightDao flightDao; + + public FlightService() { + this.flightDao = new FlightDao(); + } + + public FlightService(IFlightDao flightDao) { + this.flightDao = flightDao; + } + /** * Adds a new flight number * @@ -19,7 +32,7 @@ public class FlightService { * @return {@code true} if a flight number was added, {@code false} otherwise */ public boolean registerFlight(String flightNumber) { - throw new ExerciseNotCompletedException(); + return flightDao.register(flightNumber); } /** @@ -29,6 +42,6 @@ public boolean registerFlight(String flightNumber) { * @return a list of found flight numbers */ public List searchFlights(String query) { - throw new ExerciseNotCompletedException(); + return flightDao.findAll().stream().filter(flightId -> flightId.contains(query)).toList(); } } diff --git a/5-0-functional-programming/5-0-1-lambda-functions-map/src/main/java/com/bobocode/fp/Functions.java b/5-0-functional-programming/5-0-1-lambda-functions-map/src/main/java/com/bobocode/fp/Functions.java index a1eed08d4..87f667875 100644 --- a/5-0-functional-programming/5-0-1-lambda-functions-map/src/main/java/com/bobocode/fp/Functions.java +++ b/5-0-functional-programming/5-0-1-lambda-functions-map/src/main/java/com/bobocode/fp/Functions.java @@ -28,6 +28,11 @@ private Functions() { public static FunctionMap intFunctionMap() { FunctionMap intFunctionMap = new FunctionMap<>(); + intFunctionMap.addFunction("abs", x -> Math.abs(x)); + intFunctionMap.addFunction("sgn", x -> Integer.signum(x)); + intFunctionMap.addFunction("increment", x -> x + 1); + intFunctionMap.addFunction("decrement", x -> x - 1); + intFunctionMap.addFunction("square", x -> x * x); // todo: according to the javadoc add functions using lambda expression return intFunctionMap; diff --git a/5-0-functional-programming/5-0-2-stream-sum-of-squares/src/main/java/com/bobocode/fp/SumOfSquares.java b/5-0-functional-programming/5-0-2-stream-sum-of-squares/src/main/java/com/bobocode/fp/SumOfSquares.java index b043454d1..9969471c3 100644 --- a/5-0-functional-programming/5-0-2-stream-sum-of-squares/src/main/java/com/bobocode/fp/SumOfSquares.java +++ b/5-0-functional-programming/5-0-2-stream-sum-of-squares/src/main/java/com/bobocode/fp/SumOfSquares.java @@ -2,6 +2,8 @@ import com.bobocode.fp.exception.InvalidRangeException; +import java.util.stream.IntStream; + /** * This class allow to calculate a sum of squares of integer number in a certain range. It was implemented using * OO approach. Your job is to refactor it using functional approach. E.g. avoid using mutable variables @@ -26,10 +28,6 @@ static int calculateSumOfSquaresInRange(int startInclusive, int endInclusive) { } // todo: refactor using functional approach – instead of using for loop, use IntStream.rangeClose() - int sumOfSquares = 0; - for (int i = startInclusive; i <= endInclusive; i++) { - sumOfSquares += i * i; - } - return sumOfSquares; + return IntStream.rangeClosed(startInclusive, endInclusive).map(x -> x * x).sum(); } } diff --git a/5-0-functional-programming/5-1-1-crazy-lambdas/src/main/java/com/bobocode/fp/CrazyLambdas.java b/5-0-functional-programming/5-1-1-crazy-lambdas/src/main/java/com/bobocode/fp/CrazyLambdas.java index 78feebde2..d0d233af4 100644 --- a/5-0-functional-programming/5-1-1-crazy-lambdas/src/main/java/com/bobocode/fp/CrazyLambdas.java +++ b/5-0-functional-programming/5-1-1-crazy-lambdas/src/main/java/com/bobocode/fp/CrazyLambdas.java @@ -5,6 +5,8 @@ import java.math.BigDecimal; import java.util.Comparator; import java.util.Map; +import java.util.Objects; +import java.util.concurrent.ThreadLocalRandom; import java.util.function.*; /** @@ -27,7 +29,7 @@ public class CrazyLambdas { * @return a string supplier */ public static Supplier helloSupplier() { - throw new ExerciseNotCompletedException(); + return () -> "Hello"; } /** @@ -36,7 +38,7 @@ public static Supplier helloSupplier() { * @return a string predicate */ public static Predicate isEmptyPredicate() { - throw new ExerciseNotCompletedException(); + return (x) -> x == null || x.isEmpty(); } /** @@ -46,7 +48,15 @@ public static Predicate isEmptyPredicate() { * @return function that repeats Strings */ public static BiFunction stringMultiplier() { - throw new ExerciseNotCompletedException(); + return (x, n) -> { + if (n > 0) { + String res = x; + for (int i = 1; i < n; i++) { + res += x; + } + return res; + } else return x; + }; } /** @@ -56,7 +66,7 @@ public static BiFunction stringMultiplier() { * @return function that converts adds dollar sign */ public static Function toDollarStringFunction() { - throw new ExerciseNotCompletedException(); + return (decimal) -> "$" + decimal.toPlainString(); } /** @@ -68,7 +78,7 @@ public static Function toDollarStringFunction() { * @return a string predicate */ public static Predicate lengthInRangePredicate(int min, int max) { - throw new ExerciseNotCompletedException(); + return (x) -> x.length() >= min && x.length() <= max; } /** @@ -77,7 +87,7 @@ public static Predicate lengthInRangePredicate(int min, int max) { * @return int supplier */ public static IntSupplier randomIntSupplier() { - throw new ExerciseNotCompletedException(); + return () -> ThreadLocalRandom.current().nextInt(); } @@ -87,7 +97,7 @@ public static IntSupplier randomIntSupplier() { * @return int operation */ public static IntUnaryOperator boundedRandomIntSupplier() { - throw new ExerciseNotCompletedException(); + return (i) -> ThreadLocalRandom.current().nextInt(i); } /** @@ -96,7 +106,7 @@ public static IntUnaryOperator boundedRandomIntSupplier() { * @return square operation */ public static IntUnaryOperator intSquareOperation() { - throw new ExerciseNotCompletedException(); + return (i) -> i * i; } /** @@ -105,7 +115,7 @@ public static IntUnaryOperator intSquareOperation() { * @return binary sum operation */ public static LongBinaryOperator longSumOperation() { - throw new ExerciseNotCompletedException(); + return Long::sum; } /** @@ -114,7 +124,7 @@ public static LongBinaryOperator longSumOperation() { * @return string to int converter */ public static ToIntFunction stringToIntConverter() { - throw new ExerciseNotCompletedException(); + return Integer::parseInt; } /** @@ -125,7 +135,7 @@ public static ToIntFunction stringToIntConverter() { * @return a function supplier */ public static Supplier nMultiplyFunctionSupplier(int n) { - throw new ExerciseNotCompletedException(); + return () -> (x) -> x * n; } /** @@ -134,7 +144,7 @@ public static Supplier nMultiplyFunctionSupplier(int n) { * @return function that composes functions with trim() function */ public static UnaryOperator> composeWithTrimFunction() { - throw new ExerciseNotCompletedException(); + return (func) -> func.compose(String::trim); } /** @@ -145,7 +155,11 @@ public static UnaryOperator> composeWithTrimFunction() * @return a thread supplier */ public static Supplier runningThreadSupplier(Runnable runnable) { - throw new ExerciseNotCompletedException(); + return () -> { + var res = new Thread(runnable); + res.start(); + return res; + }; } /** @@ -154,7 +168,7 @@ public static Supplier runningThreadSupplier(Runnable runnable) { * @return a runnable consumer */ public static Consumer newThreadRunnableConsumer() { - throw new ExerciseNotCompletedException(); + return (r) -> new Thread(r).start(); } /** @@ -164,7 +178,11 @@ public static Consumer newThreadRunnableConsumer() { * @return a function that transforms runnable into a thread supplier */ public static Function> runnableToThreadSupplierFunction() { - throw new ExerciseNotCompletedException(); + return (r) -> (Supplier) () -> { + var res = new Thread(r); + res.start(); + return res; + }; } /** @@ -177,7 +195,7 @@ public static Function> runnableToThreadSupplierFunct * @return a binary function that receiver predicate and function and compose them to create a new function */ public static BiFunction functionToConditionalFunction() { - throw new ExerciseNotCompletedException(); + return (intOperation, intPredicate) -> a -> intPredicate.test(a) ? intOperation.applyAsInt(a) : a; } /** @@ -188,7 +206,12 @@ public static BiFunction funct * @return a high-order function that fetches a function from a function map by a given name or returns identity() */ public static BiFunction, String, IntUnaryOperator> functionLoader() { - throw new ExerciseNotCompletedException(); + return (stringIntUnaryOperatorMap, s) -> { + if (stringIntUnaryOperatorMap.containsKey(s)) { + return stringIntUnaryOperatorMap.get(s); + } + return IntUnaryOperator.identity(); + }; } /** @@ -206,7 +229,7 @@ public static BiFunction, String, IntUnaryOperator * @return a comparator instance */ public static > Comparator comparing(Function mapper) { - throw new ExerciseNotCompletedException(); + return Comparator.comparing((T o) -> mapper.apply(o)); } /** @@ -226,7 +249,14 @@ public static > Comparator comparing(Funct */ public static > Comparator thenComparing( Comparator comparator, Function mapper) { - throw new ExerciseNotCompletedException(); + return (o1, o2) -> { + int result = comparator.compare(o1, o2); + if (result == 0) { + return comparing(mapper).compare(o1, o2); + } else { + return result; + } + }; } /** @@ -235,7 +265,7 @@ public static > Comparator thenComparing( * @return a supplier instance */ public static Supplier>> trickyWellDoneSupplier() { - throw new ExerciseNotCompletedException(); + return () -> () -> () -> "WELL DONE!"; } } diff --git a/5-0-functional-programming/5-2-1-crazy-streams/src/main/java/com/bobocode/fp/CrazyStreams.java b/5-0-functional-programming/5-2-1-crazy-streams/src/main/java/com/bobocode/fp/CrazyStreams.java index 40ffc170f..2518c1917 100644 --- a/5-0-functional-programming/5-2-1-crazy-streams/src/main/java/com/bobocode/fp/CrazyStreams.java +++ b/5-0-functional-programming/5-2-1-crazy-streams/src/main/java/com/bobocode/fp/CrazyStreams.java @@ -1,12 +1,19 @@ package com.bobocode.fp; +import com.bobocode.fp.exception.EntityNotFoundException; import com.bobocode.model.Account; +import com.bobocode.model.Sex; import com.bobocode.util.ExerciseNotCompletedException; import lombok.AllArgsConstructor; import java.math.BigDecimal; import java.time.Month; import java.util.*; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import static java.util.stream.Collectors.*; /** * {@link CrazyStreams} is an exercise class. Each method represent some operation with a collection of accounts that @@ -22,6 +29,7 @@ */ @AllArgsConstructor public class CrazyStreams { + private Collection accounts; /** @@ -30,7 +38,7 @@ public class CrazyStreams { * @return account with max balance wrapped with optional */ public Optional findRichestPerson() { - throw new ExerciseNotCompletedException(); + return accounts.stream().max(Comparator.comparing(Account::getBalance)); } /** @@ -40,7 +48,7 @@ public Optional findRichestPerson() { * @return a list of accounts */ public List findAccountsByBirthdayMonth(Month birthdayMonth) { - throw new ExerciseNotCompletedException(); + return accounts.stream().filter(acc -> birthdayMonth.equals(acc.getBirthday().getMonth())).toList(); } /** @@ -50,7 +58,7 @@ public List findAccountsByBirthdayMonth(Month birthdayMonth) { * @return a map where key is true or false, and value is list of male, and female accounts */ public Map> partitionMaleAccounts() { - throw new ExerciseNotCompletedException(); + return accounts.stream().collect(groupingBy(a -> Sex.MALE == a.getSex())); } /** @@ -60,7 +68,7 @@ public Map> partitionMaleAccounts() { * @return a map where key is an email domain and value is a list of all account with such email */ public Map> groupAccountsByEmailDomain() { - throw new ExerciseNotCompletedException(); + return accounts.stream().collect(groupingBy(a -> a.getEmail().split("@")[1])); } /** @@ -69,7 +77,9 @@ public Map> groupAccountsByEmailDomain() { * @return total number of letters of first and last names of all accounts */ public int getNumOfLettersInFirstAndLastNames() { - throw new ExerciseNotCompletedException(); + return accounts.stream() + .mapToInt(a -> a.getFirstName().length() + a.getLastName().length()) + .sum(); } /** @@ -78,7 +88,7 @@ public int getNumOfLettersInFirstAndLastNames() { * @return total balance of all accounts */ public BigDecimal calculateTotalBalance() { - throw new ExerciseNotCompletedException(); + return accounts.stream().map(Account::getBalance).reduce(BigDecimal.ZERO, BigDecimal::add); } /** @@ -87,7 +97,7 @@ public BigDecimal calculateTotalBalance() { * @return list of accounts sorted by first and last names */ public List sortByFirstAndLastNames() { - throw new ExerciseNotCompletedException(); + return accounts.stream().sorted(Comparator.comparing(Account::getFirstName).thenComparing(Account::getLastName)).toList(); } /** @@ -97,7 +107,7 @@ public List sortByFirstAndLastNames() { * @return true if there is an account that has an email with provided domain */ public boolean containsAccountWithEmailDomain(String emailDomain) { - throw new ExerciseNotCompletedException(); + return accounts.stream().anyMatch(acc -> acc.getEmail().endsWith(emailDomain)); } /** @@ -108,7 +118,8 @@ public boolean containsAccountWithEmailDomain(String emailDomain) { * @return account balance */ public BigDecimal getBalanceByEmail(String email) { - throw new ExerciseNotCompletedException(); + return accounts.stream().filter(acc -> acc.getEmail().equals(email)).findFirst() + .orElseThrow(() -> new EntityNotFoundException("Cannot find Account by email=" + email)).getBalance(); } /** @@ -117,7 +128,7 @@ public BigDecimal getBalanceByEmail(String email) { * @return map of accounts by its ids */ public Map collectAccountsById() { - throw new ExerciseNotCompletedException(); + return accounts.stream().collect(Collectors.toMap(Account::getId, Function.identity())); } /** @@ -128,7 +139,7 @@ public Map collectAccountsById() { * @return map of account by its ids the were created in a particular year */ public Map collectBalancesByEmailForAccountsCreatedOn(int year) { - throw new ExerciseNotCompletedException(); + return accounts.stream().filter(account -> account.getCreationDate().getYear() == year).collect(Collectors.toMap(Account::getEmail, Account::getBalance)); } /** @@ -138,7 +149,8 @@ public Map collectBalancesByEmailForAccountsCreatedOn(int ye * @return a map where key is a last name and value is a set of first names */ public Map> groupFirstNamesByLastNames() { - throw new ExerciseNotCompletedException(); + return accounts.stream().collect(groupingBy(Account::getLastName, TreeMap::new, + mapping(Account::getFirstName, toSet()))); } /** @@ -148,7 +160,9 @@ public Map> groupFirstNamesByLastNames() { * @return a map where a key is a birthday month and value is comma-separated first names */ public Map groupCommaSeparatedFirstNamesByBirthdayMonth() { - throw new ExerciseNotCompletedException(); + return accounts.stream() + .collect(groupingBy(a -> a.getBirthday().getMonth(), + mapping(Account::getFirstName, joining(", ")))); } /** @@ -158,7 +172,10 @@ public Map groupCommaSeparatedFirstNamesByBirthdayMonth() { * @return a map where key is a creation month and value is total balance of all accounts created in that month */ public Map groupTotalBalanceByCreationMonth() { - throw new ExerciseNotCompletedException(); + return accounts.stream() + .collect(groupingBy(a -> a.getCreationDate().getMonth(), + mapping(Account::getBalance, + reducing(BigDecimal.ZERO, BigDecimal::add)))); } /** @@ -168,7 +185,11 @@ public Map groupTotalBalanceByCreationMonth() { * @return a map where key is a letter and value is its count in all first names */ public Map getCharacterFrequencyInFirstNames() { - throw new ExerciseNotCompletedException(); + return accounts.stream() + .map(Account::getFirstName) + .flatMapToInt(String::chars) + .mapToObj(c -> (char) c) + .collect(groupingBy(Function.identity(), counting())); } /** @@ -179,7 +200,13 @@ public Map getCharacterFrequencyInFirstNames() { * @return a map where key is a letter and value is its count ignoring case in all first and last names */ public Map getCharacterFrequencyIgnoreCaseInFirstAndLastNames(int nameLengthBound) { - throw new ExerciseNotCompletedException(); + return accounts.stream() + .flatMap(a -> Stream.of(a.getFirstName(), a.getLastName())) + .filter(s -> s.length() >= nameLengthBound) + .map(String::toLowerCase) + .flatMapToInt(String::chars) + .mapToObj(c -> (char) c) + .collect(groupingBy(Function.identity(), counting())); } } diff --git a/5-0-functional-programming/5-3-1-crazy-optionals/src/main/java/com/bobocode/fp/CrazyOptionals.java b/5-0-functional-programming/5-3-1-crazy-optionals/src/main/java/com/bobocode/fp/CrazyOptionals.java index 1ab1faa67..67dc7a8c1 100644 --- a/5-0-functional-programming/5-3-1-crazy-optionals/src/main/java/com/bobocode/fp/CrazyOptionals.java +++ b/5-0-functional-programming/5-3-1-crazy-optionals/src/main/java/com/bobocode/fp/CrazyOptionals.java @@ -16,6 +16,8 @@ import java.util.Optional; import java.util.OptionalDouble; +import static java.util.Comparator.comparing; + /** * {@link CrazyOptionals} is an exercise class. Each method represents some operation with a {@link Account} and * should be implemented using Optional API. Every method that is not implemented yet throws @@ -37,7 +39,7 @@ public class CrazyOptionals { * @return optional object that holds text */ public static Optional optionalOfString(@Nullable String text) { - throw new ExerciseNotCompletedException(); + return Optional.ofNullable(text); } /** @@ -47,7 +49,7 @@ public static Optional optionalOfString(@Nullable String text) { * @param amount money to deposit */ public static void deposit(AccountProvider accountProvider, BigDecimal amount) { - throw new ExerciseNotCompletedException(); + accountProvider.getAccount().ifPresent(acc -> acc.setBalance(acc.getBalance().add(amount))); } /** @@ -57,7 +59,7 @@ public static void deposit(AccountProvider accountProvider, BigDecimal amount) { * @return optional object that holds account */ public static Optional optionalOfAccount(@Nonnull Account account) { - throw new ExerciseNotCompletedException(); + return Optional.of(account); } /** @@ -69,7 +71,7 @@ public static Optional optionalOfAccount(@Nonnull Account account) { * @return account from provider or defaultAccount */ public static Account getAccount(AccountProvider accountProvider, Account defaultAccount) { - throw new ExerciseNotCompletedException(); + return accountProvider.getAccount().orElse(defaultAccount); } /** @@ -80,7 +82,7 @@ public static Account getAccount(AccountProvider accountProvider, Account defaul * @param accountService */ public static void processAccount(AccountProvider accountProvider, AccountService accountService) { - throw new ExerciseNotCompletedException(); + accountProvider.getAccount().ifPresentOrElse(accountService::processAccount, accountService::processWithNoAccount); } /** @@ -91,7 +93,7 @@ public static void processAccount(AccountProvider accountProvider, AccountServic * @return provided or generated account */ public static Account getOrGenerateAccount(AccountProvider accountProvider) { - throw new ExerciseNotCompletedException(); + return accountProvider.getAccount().orElseGet(Accounts::generateAccount); } /** @@ -101,7 +103,7 @@ public static Account getOrGenerateAccount(AccountProvider accountProvider) { * @return optional balance */ public static Optional retrieveBalance(AccountProvider accountProvider) { - throw new ExerciseNotCompletedException(); + return accountProvider.getAccount().map(Account::getBalance); } /** @@ -112,7 +114,8 @@ public static Optional retrieveBalance(AccountProvider accountProvid * @return provided account */ public static Account getAccount(AccountProvider accountProvider) { - throw new ExerciseNotCompletedException(); + return accountProvider.getAccount() + .orElseThrow(() -> new AccountNotFoundException("No Account provided!")); } /** @@ -122,7 +125,8 @@ public static Account getAccount(AccountProvider accountProvider) { * @return optional credit balance */ public static Optional retrieveCreditBalance(CreditAccountProvider accountProvider) { - throw new ExerciseNotCompletedException(); + return accountProvider.getAccount() + .flatMap(CreditAccount::getCreditBalance); } @@ -134,7 +138,8 @@ public static Optional retrieveCreditBalance(CreditAccountProvider a * @return optional gmail account */ public static Optional retrieveAccountGmail(AccountProvider accountProvider) { - throw new ExerciseNotCompletedException(); + return accountProvider.getAccount() + .filter(account -> account.getEmail().endsWith("gmail.com")); } /** @@ -147,7 +152,9 @@ public static Optional retrieveAccountGmail(AccountProvider accountProv * @return account got from either accountProvider or fallbackProvider */ public static Account getAccountWithFallback(AccountProvider accountProvider, AccountProvider fallbackProvider) { - throw new ExerciseNotCompletedException(); + return accountProvider.getAccount() + .or(fallbackProvider::getAccount) + .orElseThrow(); } /** @@ -158,7 +165,9 @@ public static Account getAccountWithFallback(AccountProvider accountProvider, Ac * @return account with the highest balance */ public static Account getAccountWithMaxBalance(List accounts) { - throw new ExerciseNotCompletedException(); + return accounts.stream() + .max(comparing(Account::getBalance)) // as you probably know Stream#min() and Stream#max() return Optional + .orElseThrow(); } /** @@ -168,7 +177,10 @@ public static Account getAccountWithMaxBalance(List accounts) { * @return the lowest balance values */ public static OptionalDouble findMinBalanceValue(List accounts) { - throw new ExerciseNotCompletedException(); + return accounts.stream() + .map(Account::getBalance) + .mapToDouble(BigDecimal::doubleValue) + .min(); } /** @@ -178,7 +190,9 @@ public static OptionalDouble findMinBalanceValue(List accounts) { * @param accountService */ public static void processAccountWithMaxBalance(List accounts, AccountService accountService) { - throw new ExerciseNotCompletedException(); + accounts.stream() + .max(comparing(Account::getBalance)) + .ifPresent(accountService::processAccount); } /** @@ -188,7 +202,11 @@ public static void processAccountWithMaxBalance(List accounts, AccountS * @return total credit balance */ public static double calculateTotalCreditBalance(List accounts) { - throw new ExerciseNotCompletedException(); + return accounts.stream() + .map(CreditAccount::getCreditBalance) + .flatMap(Optional::stream) + .mapToDouble(BigDecimal::doubleValue) + .sum(); } } diff --git a/5-0-functional-programming/5-4-1-fun-prime-numbers/src/main/java/com/bobocode/fp/PrimeNumbers.java b/5-0-functional-programming/5-4-1-fun-prime-numbers/src/main/java/com/bobocode/fp/PrimeNumbers.java index e4a99188d..e326fb472 100644 --- a/5-0-functional-programming/5-4-1-fun-prime-numbers/src/main/java/com/bobocode/fp/PrimeNumbers.java +++ b/5-0-functional-programming/5-4-1-fun-prime-numbers/src/main/java/com/bobocode/fp/PrimeNumbers.java @@ -5,6 +5,7 @@ import java.util.List; import java.util.Map; import java.util.function.IntConsumer; +import java.util.stream.Collectors; import java.util.stream.IntStream; /** @@ -30,7 +31,13 @@ private PrimeNumbers() { * @return an infinite int stream of prime numbers */ public static IntStream stream() { - throw new ExerciseNotCompletedException(); // todo: create an infinite stream of ints, then filter prime numbs + return IntStream.iterate(2, i -> i + 1).filter(PrimeNumbers::isPrime); + } + + private static boolean isPrime(int number) { + if (number == 2) return true; + if (number < 2 || number % 2 == 0) return false; + return IntStream.rangeClosed(3, (int) Math.sqrt(number)).noneMatch(i -> number % i == 0); } /** @@ -40,7 +47,7 @@ public static IntStream stream() { * @return an int stream of prime numbers with a specified size */ public static IntStream stream(int size) { - throw new ExerciseNotCompletedException(); // todo: use the prev to generate a stream method but limit its size + return stream().limit(size); } /** @@ -51,7 +58,7 @@ public static IntStream stream(int size) { * @return the sum of n prime numbers */ public static int sum(int n) { - throw new ExerciseNotCompletedException(); // todo: use prev method and calculate the sum + return stream(n).sum(); } @@ -61,7 +68,7 @@ public static int sum(int n) { * @return a list of collected prime numbers */ public static List list(int n) { - throw new ExerciseNotCompletedException(); // todo: collect prime numbers into the list + return stream(n).boxed().toList(); } /** @@ -71,7 +78,7 @@ public static List list(int n) { * @param consumer a logic that should be applied to the found prime number */ public static void processByIndex(int idx, IntConsumer consumer) { - throw new ExerciseNotCompletedException(); // todo: find an element in the stream by index and process it + stream().skip(idx).findFirst().ifPresent(consumer); } /** @@ -85,6 +92,6 @@ public static void processByIndex(int idx, IntConsumer consumer) { * @return a map with prime number grouped by the amount of digits */ public static Map> groupByAmountOfDigits(int n) { - throw new ExerciseNotCompletedException(); // todo: group n prime numbers by the amount of digits + return stream(n).boxed().collect(Collectors.groupingBy(i -> String.valueOf(i).length())); } }