From 348386cc53d0d0ed4386718d396e4ad9f3c0f662 Mon Sep 17 00:00:00 2001 From: MortyMerr <anton.nazarof@mail.ru> Date: Thu, 6 Jul 2017 15:45:52 +0300 Subject: [PATCH 1/2] part-3 --- .../java/lambda/part3/exercise/Mapping.java | 82 ++++++++++++------- 1 file changed, 52 insertions(+), 30 deletions(-) diff --git a/src/test/java/lambda/part3/exercise/Mapping.java b/src/test/java/lambda/part3/exercise/Mapping.java index c0a814a..af0a585 100644 --- a/src/test/java/lambda/part3/exercise/Mapping.java +++ b/src/test/java/lambda/part3/exercise/Mapping.java @@ -3,6 +3,7 @@ import data.Employee; import data.JobHistoryEntry; import data.Person; +import jdk.nashorn.internal.scripts.JO; import org.junit.Test; import java.util.ArrayList; @@ -18,6 +19,15 @@ public class Mapping { + private List<JobHistoryEntry> addOneYear(List<JobHistoryEntry> jobs) { + return new MapHelper<>(jobs).map(j -> j.withDuration(j.getDuration() + 1)).getList(); + } + + private List<JobHistoryEntry> upperCaseQa(List<JobHistoryEntry> jobs) { + return new MapHelper<>(jobs).map(j -> j.getPosition().equals("qa") ? j.withPosition(j.getPosition().toUpperCase()) : j).getList(); + //TOASK how should i format this code? Should i use statement lambda for better reading? + } + private static class MapHelper<T> { private final List<T> list; @@ -32,8 +42,11 @@ public List<T> getList() { // [T] -> (T -> R) -> [R] // [T1, T2, T3] -> (T -> R) -> [R1, R2, R3] public <R> MapHelper<R> map(Function<T, R> f) { - // TODO - throw new UnsupportedOperationException(); + final List<R> result = new ArrayList<>(); + for (T t : list) { + result.add(f.apply(t)); + } + return new MapHelper<>(result); } // [T] -> (T -> [R]) -> [R] @@ -41,12 +54,12 @@ public <R> MapHelper<R> map(Function<T, R> f) { // map: [T, T, T], T -> [R] => [[], [R1, R2], [R3, R4, R5]] // flatMap: [T, T, T], T -> [R] => [R1, R2, R3, R4, R5] public <R> MapHelper<R> flatMap(Function<T, List<R>> f) { - final List<R> result = new ArrayList<R>(); + final List<R> result = new ArrayList<>(); list.forEach((T t) -> - f.apply(t).forEach(result::add) + result.addAll(f.apply(t)) ); - return new MapHelper<R>(result); + return new MapHelper<>(result); } } @@ -76,12 +89,9 @@ public void mapping() { final List<Employee> 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 - * */ - .getList(); + .map(e -> e.withPerson(e.getPerson().withFirstName("John"))) + .map(e -> e.withJobHistory(addOneYear(e.getJobHistory()))) + .map(e -> e.withJobHistory(upperCaseQa(e.getJobHistory()))).getList(); final List<Employee> expectedResult = Arrays.asList( @@ -110,8 +120,13 @@ public void mapping() { private static class LazyMapHelper<T, R> { + private final Function<T, R> function; + private final List<T> list; + public LazyMapHelper(List<T> list, Function<T, R> function) { + this.list = list; + this.function = function; } public static <T> LazyMapHelper<T, T> from(List<T> list) { @@ -119,35 +134,45 @@ public static <T> LazyMapHelper<T, T> from(List<T> list) { } public List<R> force() { - // TODO - throw new UnsupportedOperationException(); + final List<R> result = new ArrayList<>(); + for (T t : list) { + result.add(function.apply(t)); + } + return result; } public <R2> LazyMapHelper<T, R2> map(Function<R, R2> f) { - // TODO - throw new UnsupportedOperationException(); + return new LazyMapHelper<>(list, function.andThen(f)); } - } private static class LazyFlatMapHelper<T, R> { + private List<T> list; + private Function<T, List<R>> function; public LazyFlatMapHelper(List<T> list, Function<T, List<R>> function) { + this.list = list; + this.function = function; } public static <T> LazyFlatMapHelper<T, T> from(List<T> list) { - throw new UnsupportedOperationException(); + return new LazyFlatMapHelper<>(list, Arrays::asList); } public List<R> force() { - // TODO - throw new UnsupportedOperationException(); + final List<R> result = new ArrayList<>(); + for (T t : list) { + result.addAll(function.apply(t)); + } + return result; } - // TODO filter // (T -> boolean) -> (T -> [T]) // filter: [T1, T2] -> (T -> boolean) -> [T2] // flatMap": [T1, T2] -> (T -> [T]) -> [T2] + public LazyFlatMapHelper<T, R> filter(final Predicate<T> predicate) { + return new LazyFlatMapHelper<>(list, e -> predicate.test(e) ? function.apply(e) : Collections.emptyList()); + } public <R2> LazyFlatMapHelper<T, R2> map(Function<R, R2> f) { final Function<R, List<R2>> listFunction = rR2TorListR2(f); @@ -156,17 +181,15 @@ public <R2> LazyFlatMapHelper<T, R2> map(Function<R, R2> f) { // (R -> R2) -> (R -> [R2]) private <R2> Function<R, List<R2>> rR2TorListR2(Function<R, R2> f) { - throw new UnsupportedOperationException(); + return e -> Collections.singletonList(f.apply(e)); } - // TODO * public <R2> LazyFlatMapHelper<T, R2> flatMap(Function<R, List<R2>> f) { - throw new UnsupportedOperationException(); + return new LazyFlatMapHelper<>(list, t -> new MapHelper<>(function.apply(t)).flatMap(f).getList()); } } - @Test public void lazy_mapping() { final List<Employee> employees = @@ -193,12 +216,9 @@ public void lazy_mapping() { final List<Employee> mappedEmployees = LazyMapHelper.from(employees) - /* - .map(TODO) // change name to John - .map(TODO) // add 1 year to experience duration - .map(TODO) // replace qa with QA - * */ - .force(); + .map(e -> e.withPerson(e.getPerson().withFirstName("John"))) + .map(e -> e.withJobHistory(addOneYear(e.getJobHistory()))) + .map(e -> e.withJobHistory(upperCaseQa(e.getJobHistory()))).force(); final List<Employee> expectedResult = Arrays.asList( @@ -225,3 +245,5 @@ public void lazy_mapping() { assertEquals(mappedEmployees, expectedResult); } } + + From e04846adff35b8604faa301c79edf46225e72b1c Mon Sep 17 00:00:00 2001 From: MortyMerr <anton.nazarof@mail.ru> Date: Thu, 6 Jul 2017 20:23:25 +0300 Subject: [PATCH 2/2] ReachIter, Traversable --- .../java/lambda/part3/exercise/FilterMap.java | 2 + .../java/lambda/part3/exercise/Mapping.java | 98 ++++++++++- .../part3/exercise/ReachIterableTest.java | 152 ++++++++++++++++++ 3 files changed, 246 insertions(+), 6 deletions(-) create mode 100644 src/test/java/lambda/part3/exercise/ReachIterableTest.java diff --git a/src/test/java/lambda/part3/exercise/FilterMap.java b/src/test/java/lambda/part3/exercise/FilterMap.java index 178190e..30db765 100644 --- a/src/test/java/lambda/part3/exercise/FilterMap.java +++ b/src/test/java/lambda/part3/exercise/FilterMap.java @@ -2,6 +2,7 @@ import java.util.ArrayList; import java.util.List; +import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Predicate; @@ -30,6 +31,7 @@ public Function<T, R> getFunction() { } } + public static class LazyCollectionHelper<T> { private final List<Container<Object, Object>> actions; private final List<T> list; diff --git a/src/test/java/lambda/part3/exercise/Mapping.java b/src/test/java/lambda/part3/exercise/Mapping.java index af0a585..ec8b81f 100644 --- a/src/test/java/lambda/part3/exercise/Mapping.java +++ b/src/test/java/lambda/part3/exercise/Mapping.java @@ -1,16 +1,12 @@ package lambda.part3.exercise; +import com.sun.org.apache.regexp.internal.RE; import data.Employee; import data.JobHistoryEntry; import data.Person; -import jdk.nashorn.internal.scripts.JO; 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; @@ -189,6 +185,96 @@ public <R2> LazyFlatMapHelper<T, R2> flatMap(Function<R, List<R2>> f) { } } + interface Traversable<T> { + void forEach(Consumer<T> c); + + default List<T> toList() { + final List<T> result = new ArrayList<>(); + forEach(result::add); + return result; + } + + static <T> Traversable<T> from(List<T> list) { + return new Traversable<T>() { + @Override + public void forEach(Consumer<T> c) { + list.forEach(c); + } + }; + } + + default Traversable<T> filter(Predicate<T> p) { + return c -> this.forEach(v -> { + if (p.test(v)) { + c.accept(v); + } + }); + } + + default <R> Traversable<R> flatMap(Function<T, Traversable<R>> f) { + return c -> this.forEach(t -> f.apply(t).forEach(c)); + } + + default <R> Traversable<R> map(Function<T, R> f) { + return c -> this.forEach(t -> c.accept(f.apply(t))); + } + } + + @Test + public void traversable() { + final List<Employee> 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") + )), + new Employee( + new Person("c", "White", 50), + Collections.singletonList( + new JobHistoryEntry(5, "qa", "epam") + )) + ); + + final List<Employee> filteredEmployees = + Traversable.from(employees) + .filter(e -> e.getPerson().getFirstName().equals("a")).toList(); + + final List<Employee> expectedResult = + Arrays.asList( + new Employee( + new Person("a", "Galt", 30), + Arrays.asList( + new JobHistoryEntry(2, "dev", "epam"), + new JobHistoryEntry(1, "dev", "google") + )) + ); + + assertEquals(filteredEmployees, expectedResult); + + final List<JobHistoryEntry> flattedJobs = + Traversable.from(employees) + .filter(e -> e.getPerson().getLastName().length() < 5) + .flatMap(e -> Traversable.from(e.getJobHistory())).toList(); + + final List<JobHistoryEntry> jobs = Arrays.asList( + new JobHistoryEntry(2, "dev", "epam"), + new JobHistoryEntry(1, "dev", "google"), + new JobHistoryEntry(3, "qa", "yandex"), + new JobHistoryEntry(1, "qa", "epam"), + new JobHistoryEntry(1, "dev", "abc") + ); + + assertEquals(flattedJobs, jobs); + } @Test public void lazy_mapping() { diff --git a/src/test/java/lambda/part3/exercise/ReachIterableTest.java b/src/test/java/lambda/part3/exercise/ReachIterableTest.java new file mode 100644 index 0000000..20ef599 --- /dev/null +++ b/src/test/java/lambda/part3/exercise/ReachIterableTest.java @@ -0,0 +1,152 @@ +package lambda.part3.exercise; + +import com.google.common.collect.FluentIterable; +import com.sun.org.apache.xpath.internal.operations.Bool; +import org.junit.Test; + +import javax.xml.ws.Holder; +import java.util.*; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Predicate; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; + +/** + * Created by antonnazarov on 06.07.17. + */ +public class ReachIterableTest { + interface ReachIterable<T> { + default boolean anyMatch(final Predicate<T> p) { + return firstMatch(p).isPresent(); + } + + default boolean allMatch(final Predicate<T> p) { + return !anyMatch(p.negate()); + } + + default boolean noneMatch(final Predicate<T> p) { + return !anyMatch(p); + } + + default Optional<T> firstMatch(final Predicate<T> p) { + Holder<Optional<T>> founded = new Holder<>(Optional.empty()); + while (tryGet(t -> { + if (p.test(t)) { + founded.value = Optional.of(t); + } + }) && (!founded.value.isPresent())) { + ; + } + + return founded.value; + } + + default ReachIterable<T> filter(final Predicate<T> p) { + return c -> this.tryGet(v -> { + if (p.test(v)) { + c.accept(v); + } + }); + } + + + default <R> ReachIterable<R> map(final Function<T, R> f) { + return c -> this.tryGet(e -> c.accept(f.apply(e))); + } + + default <R> ReachIterable<R> flatMap(final Function<T, ReachIterable<R>> f) { + //TOAPOLOGIZE Code in this method is not really my. I cheated to view the result. + + ReachIterable<T> self = this; + return new ReachIterable<R>() { + ReachIterable<R> tmp; + boolean selfHasNext = false, + tmpHasNext = false; + + @Override + public boolean tryGet(final Consumer<R> c) { + if (!tmpHasNext) { + selfHasNext = self.tryGet(e -> tmp = f.apply(e)); + } + + tmpHasNext = tmp.tryGet(c); + + return tmpHasNext || selfHasNext; + } + }; + } + + static <T> ReachIterable<T> from(List<T> list) { + final Iterator<T> i = list.iterator(); + return c -> { + if (i.hasNext()) { + c.accept(i.next()); + } + return i.hasNext(); + }; + } + + default List<T> force() { + final List<T> result = new ArrayList<>(); + while (tryGet(result::add)) { + ; + } + return result; + } + + boolean tryGet(final Consumer<T> c); + } + + private final List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5); + + @Test + public void reachIterableFilter() { + + List<Integer> filteredNumbers = ReachIterable.from(numbers).filter(t -> (t % 2) == 0).force(); + + assertEquals(filteredNumbers, Arrays.asList(2, 4)); + } + + @Test + public void reachIterableMap() { + final List<Integer> mappedNumbers = ReachIterable.from(numbers).map(t -> t * 2).force(); + assertEquals(mappedNumbers, Arrays.asList(2, 4, 6, 8, 10)); + } + + @Test + public void reachIteableFlatted() { + final List<Integer> mappedNumbers = ReachIterable.from(numbers) + .filter(e -> e < 3) + .flatMap(e -> ReachIterable.from(Arrays.asList(e * 2, e * 3))) + .force(); + + assertEquals(mappedNumbers, Arrays.asList(2, 3, 4, 6)); + } + + @Test + public void anyMatches() { + assertEquals(ReachIterable.from(numbers).anyMatch(t -> t.equals(2)), true); + assertEquals(ReachIterable.from(numbers).anyMatch(t -> t.equals(7)), false); + } + + @Test + public void firstMathces() { + assertEquals(ReachIterable.from(numbers).firstMatch(t -> t.equals(2)).get(), numbers.get(1)); + assertEquals(ReachIterable.from(numbers).firstMatch(t -> t.equals(7)).isPresent(), false); + } + + @Test + public void allMatches() { + assertEquals(ReachIterable.from(numbers).allMatch(e -> e < 10), true); + assertEquals(ReachIterable.from(numbers).allMatch(e -> e.equals(1)), false); + } + + @Test + public void noneMatches() { + assertEquals(ReachIterable.from(numbers).noneMatch(e -> e.equals(1)), false); + assertEquals(ReachIterable.from(numbers).noneMatch(e -> e.equals(10)), true); + } +}