diff --git a/src/test/java/lambda/part3/exercise/Mapping.java b/src/test/java/lambda/part3/exercise/Mapping.java index c0a814a..0a75680 100644 --- a/src/test/java/lambda/part3/exercise/Mapping.java +++ b/src/test/java/lambda/part3/exercise/Mapping.java @@ -5,11 +5,7 @@ import data.Person; import org.junit.Test; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.function.BiConsumer; +import java.util.*; import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Predicate; @@ -32,8 +28,10 @@ public List getList() { // [T] -> (T -> R) -> [R] // [T1, T2, T3] -> (T -> R) -> [R1, R2, R3] public MapHelper map(Function f) { - // TODO - throw new UnsupportedOperationException(); + final List result = new ArrayList<>(); + list.forEach(t -> + result.add(f.apply(t))); + return new MapHelper<>(result); } // [T] -> (T -> [R]) -> [R] @@ -76,11 +74,9 @@ public void mapping() { final List mappedEmployees = new MapHelper<>(employees) - /* - .map(TODO) // change name to John .map(e -> e.withPerson(e.getPerson().withFirstName("John"))) - .map(TODO) // add 1 year to experience duration .map(e -> e.withJobHistory(addOneYear(e.getJobHistory()))) - .map(TODO) // replace qa with QA - * */ + .map(e -> e.withPerson(e.getPerson().withFirstName("John"))) + .map(e -> e.withJobHistory(addOneYear(e.getJobHistory()))) + .map(e -> e.withJobHistory(qaToUpperCase(e.getJobHistory()))) .getList(); final List expectedResult = @@ -108,10 +104,30 @@ public void mapping() { assertEquals(mappedEmployees, expectedResult); } + // [JobHistoryEntry] -> (JobHistoryEntry -> JobHistoryEntry) -> [JobHistoryEntry] + private static List qaToUpperCase(List list) { + return new MapHelper<>(list) + .map(entry -> + entry.getPosition().equals("qa") ? entry.withPosition("QA") : entry) + .getList(); + } + + // [JobHistoryEntry] -> (JobHistoryEntry -> JobHistoryEntry) -> [JobHistoryEntry] + private static List addOneYear(List list) { + return new MapHelper<>(list) + .map(entry -> + entry.withDuration(entry.getDuration() + 1)) + .getList(); + } private static class LazyMapHelper { - public LazyMapHelper(List list, Function function) { + private final List list; + private final Function function; + + private LazyMapHelper(List list, Function function) { + this.list = list; + this.function = function; } public static LazyMapHelper from(List list) { @@ -119,53 +135,174 @@ public static LazyMapHelper from(List list) { } public List force() { - // TODO - throw new UnsupportedOperationException(); + return new MapHelper<>(list).map(function).getList(); } public LazyMapHelper map(Function f) { - // TODO - throw new UnsupportedOperationException(); + Function newFunction = function.andThen(f); + return new LazyMapHelper<>(list, newFunction); } - } - private static class LazyFlatMapHelper { + interface ReachIterable { + //hasNext and next + boolean tryGet(Consumer c); + - public LazyFlatMapHelper(List list, Function> function) { + //TODO boolean anyMatch(Predicate p) + default boolean anyMatch(Predicate p) { + return firstMatch(p).isPresent(); } - public static LazyFlatMapHelper from(List list) { - throw new UnsupportedOperationException(); + //TODO boolean allMatch(Predicate p) + default boolean allMatch(Predicate p) { + final List allMatch = Collections.singletonList(true); + final List keep = Collections.singletonList(true); + Consumer consumer = t -> { + if (keep.get(0) && !p.test(t)) { + allMatch.set(0, false); + keep.set(0, false); + } + }; + while (tryGet(consumer)) {} + return allMatch.get(0); } - public List force() { - // TODO - throw new UnsupportedOperationException(); + //TODO boolean noneMatch(Predicate p) + default boolean noneMatch(Predicate p) { + return !allMatch(p); } - // TODO filter - // (T -> boolean) -> (T -> [T]) - // filter: [T1, T2] -> (T -> boolean) -> [T2] - // flatMap": [T1, T2] -> (T -> [T]) -> [T2] + //TODO Optional firstMatch(Predicate p) + default Optional firstMatch(Predicate p) { + final List> optionals = Collections.singletonList(Optional.empty()); + final List keep = Collections.singletonList(true); + Consumer consumer = t -> { + if (keep.get(0) && p.test(t)) { + optionals.set(0, Optional.ofNullable(t)); + keep.set(0, false); + } + }; + while (tryGet(consumer)) {} + return optionals.get(0); + } + + static ReachIterable from(List list) { + return new ReachIterable() { + @Override + public boolean tryGet(Consumer c) { + Iterator iterator = list.iterator(); + if (iterator.hasNext()) { + c.accept(iterator.next()); + return true; + } + return false; + } + }; + } + } - public LazyFlatMapHelper map(Function f) { - final Function> listFunction = rR2TorListR2(f); - return flatMap(listFunction); + interface Traversable { + void forEach(Consumer c); + + default Traversable filter(Predicate p) { + final Traversable self = this; + return new Traversable() { + @Override + public void forEach(Consumer c) { + self.forEach(t -> { + if (p.test(t)) + c.accept(t); + }); + } + }; } - // (R -> R2) -> (R -> [R2]) - private Function> rR2TorListR2(Function f) { - throw new UnsupportedOperationException(); + default Traversable flatMap(Function> f) { + final Traversable self = this; + return new Traversable() { + @Override + public void forEach(Consumer c) { + self.forEach( + t -> f.apply(t) + .forEach(c)); + } + }; } - // TODO * - public LazyFlatMapHelper flatMap(Function> f) { - throw new UnsupportedOperationException(); + default Traversable map(Function f) { + final Traversable self = this; + return new Traversable() { + @Override + public void forEach(Consumer c) { + self.forEach(t -> c.accept(f.apply(t))); + } + }; } + + default List toList() { + final List list = new ArrayList<>(); + forEach(list::add); + return list; + } + + static Traversable from(List list) { + return new Traversable() { + @Override + public void forEach(Consumer c) { + list.forEach(c); + } + }; + } + } + + @Test + public void testFlatMap() { + final List employees = + Arrays.asList( + new Employee( + new Person("a", "Galt", 30), + Arrays.asList( + new JobHistoryEntry(2, "dev", "epam"), + new JobHistoryEntry(1, "dev", "google") + )), + new Employee( + new Person("b", "Doe", 40), + Arrays.asList( + new JobHistoryEntry(3, "qa", "yandex"), + new JobHistoryEntry(1, "qa", "epam"), + new JobHistoryEntry(1, "dev", "abc") + )) + ); + + System.err.println( + Arrays.toString( + Traversable.from(employees).flatMap(Employee::getJobHistory).toList().toArray())); } + @Test + public void testFilter() { + final List employees = + Arrays.asList( + new Employee( + new Person("a", "Galt", 30), + Arrays.asList( + new JobHistoryEntry(2, "dev", "epam"), + new JobHistoryEntry(1, "dev", "google") + )), + new Employee( + new Person("b", "Doe", 40), + Arrays.asList( + new JobHistoryEntry(3, "qa", "yandex"), + new JobHistoryEntry(1, "qa", "epam"), + new JobHistoryEntry(1, "dev", "abc") + )) + ); + System.err.println( + Arrays.toString( + Traversable.from(employees).filter(e -> e.getPerson().getFirstName().equals("a")).toList().toArray())); + } @Test public void lazy_mapping() { @@ -193,11 +330,9 @@ public void lazy_mapping() { final List mappedEmployees = LazyMapHelper.from(employees) - /* - .map(TODO) // change name to John - .map(TODO) // add 1 year to experience duration - .map(TODO) // replace qa with QA - * */ + .map(e -> e.withPerson(e.getPerson().withFirstName("John"))) // change name to John + .map(e -> e.withJobHistory(addOneYear(e.getJobHistory()))) // add 1 year to experience duration + .map(e -> e.withJobHistory(qaToUpperCase(e.getJobHistory()))) // replace qa with QA .force(); final List expectedResult =