diff --git a/src/test/java/part2/exercise/CollectorsExercise1.java b/src/test/java/part2/exercise/CollectorsExercise1.java index 46b6765..6a69e06 100755 --- a/src/test/java/part2/exercise/CollectorsExercise1.java +++ b/src/test/java/part2/exercise/CollectorsExercise1.java @@ -6,25 +6,19 @@ import org.junit.Test; import java.util.*; -import java.util.concurrent.ThreadLocalRandom; -import java.util.function.BiConsumer; -import java.util.function.BinaryOperator; -import java.util.function.Function; -import java.util.function.Supplier; -import java.util.stream.Collector; import java.util.stream.Collectors; -import java.util.stream.IntStream; -import java.util.stream.Stream; -import static java.util.stream.Collectors.toList; +import static java.util.stream.Collectors.*; +import static org.junit.Assert.assertEquals; public class CollectorsExercise1 { @Test public void getTheCoolestOne() { - final Map coolestByPosition = getCoolestByPosition(getEmployees()); + final Map coolestByPositionFirst = getCoolestByPositionFirst(getEmployees()); + final Map coolestByPositionSecond = getCoolestByPositionSecond(getEmployees()); - coolestByPosition.forEach((position, person) -> System.out.println(position + " -> " + person)); + assertEquals(coolestByPositionFirst, coolestByPositionSecond); } private static class PersonPositionDuration { @@ -52,17 +46,40 @@ public int getDuration() { } // With the longest duration on single job - private Map getCoolestByPosition(List employees) { + private Map getCoolestByPositionFirst(List employees) { // First option // Collectors.maxBy // Collectors.collectingAndThen // Collectors.groupingBy + // TODO + return employees.stream() + .flatMap(e -> e.getJobHistory().stream() + .map(j -> new PersonPositionDuration(e.getPerson(), j.getPosition(), j.getDuration()))) + .collect( + groupingBy( + PersonPositionDuration::getPosition, + collectingAndThen( + maxBy(Comparator.comparingInt(PersonPositionDuration::getDuration)), + o -> o.orElseThrow(IllegalStateException::new).getPerson() + ) + ) + ); + } + private Map getCoolestByPositionSecond(List employees) { // Second option // Collectors.toMap // iterate twice: stream...collect(...).stream()... // TODO - throw new UnsupportedOperationException(); + return employees.stream() + .flatMap(e -> e.getJobHistory().stream() + .map(j -> new PersonPositionDuration(e.getPerson(), j.getPosition(), j.getDuration()))) + .collect(toMap( + PersonPositionDuration::getPosition, + o -> new PersonPositionDuration(o.getPerson(), null, o.getDuration()), + (p1, p2) -> p1.getDuration() > p2.getDuration() ? p1 : p2 + )).entrySet().stream() + .collect(toMap(Map.Entry::getKey, o -> o.getValue().getPerson())); } @Test @@ -76,7 +93,27 @@ public void getTheCoolestOne2() { // { John Doe, [{dev, google, 4}, {dev, epam, 4}] } предпочтительнее, чем { A B, [{dev, google, 6}, {QA, epam, 100}]} private Map getCoolestByPosition2(List employees) { // TODO - throw new UnsupportedOperationException(); + return employees.stream() + .flatMap(e -> e.getJobHistory().stream() + .map(j -> new PersonPositionDuration(e.getPerson(), j.getPosition(), j.getDuration()))) + .collect( + groupingBy( + PersonPositionDuration::getPosition, + collectingAndThen( + groupingBy( + PersonPositionDuration::getPerson, + summingInt(PersonPositionDuration::getDuration) + ), + m -> { + Map.Entry maxEntry = null; + for (Map.Entry entry : m.entrySet()) + if (maxEntry == null || entry.getValue().compareTo(maxEntry.getValue()) > 0) + maxEntry = entry; + return maxEntry.getKey(); + } + ) + ) + ); } private List getEmployees() { @@ -151,7 +188,7 @@ private List getEmployees() { new Employee( new Person("Bob", "White", 31), Collections.singletonList( - new JobHistoryEntry(6, "QA", "epam") + new JobHistoryEntry(10, "QA", "epam") )) ); } diff --git a/src/test/java/part2/exercise/CollectorsExercise2.java b/src/test/java/part2/exercise/CollectorsExercise2.java index 00fda00..5eb51f7 100755 --- a/src/test/java/part2/exercise/CollectorsExercise2.java +++ b/src/test/java/part2/exercise/CollectorsExercise2.java @@ -1,8 +1,5 @@ package part2.exercise; -import data.Employee; -import data.JobHistoryEntry; -import data.Person; import org.junit.Test; import java.util.*; @@ -12,11 +9,11 @@ import java.util.function.Function; import java.util.function.Supplier; import java.util.stream.Collector; -import java.util.stream.Collectors; import java.util.stream.IntStream; import java.util.stream.Stream; -import static java.util.stream.Collectors.toList; +import static java.util.stream.Collectors.*; +import static org.junit.Assert.assertEquals; public class CollectorsExercise2 { @@ -28,7 +25,7 @@ private static String generateString() { return IntStream.range(0, length) .mapToObj(letters::charAt) .map(Object::toString) - .collect(Collectors.joining()); + .collect(joining()); } private static String[] generateStringArray(int length) { @@ -99,20 +96,26 @@ public Value getValue() { } } - public static List generatePairs(int idCount, int length) { + public static Set generatePairs(int idCount, int length) { final String[] ids = generateStringArray(idCount); return Stream.generate(() -> new Pair(new Key(pickString(ids)), new Value(pickString(ids)))) .limit(length) - .collect(toList()); + .collect(toSet()); } private static class SubResult { private final Map> subResult; - private final Map> knownKeys; + private final Map knownKeys; private final Map> valuesWithoutKeys; - public SubResult(Map> subResult, Map> knownKeys, Map> valuesWithoutKeys) { + public SubResult(Map> subResult) { + this.subResult = subResult; + this.knownKeys = null; + this.valuesWithoutKeys = null; + } + + public SubResult(Map> subResult, Map knownKeys, Map> valuesWithoutKeys) { this.subResult = subResult; this.knownKeys = knownKeys; this.valuesWithoutKeys = valuesWithoutKeys; @@ -126,7 +129,7 @@ public Map> getValuesWithoutKeys() { return valuesWithoutKeys; } - public Map> getKnownKeys() { + public Map getKnownKeys() { return knownKeys; } } @@ -135,22 +138,34 @@ private static class MapPair { private final Map keyById; private final Map> valueById; - public MapPair() { + MapPair() { this(new HashMap<>(), new HashMap<>()); } - public MapPair(Map keyById, Map> valueById) { + MapPair(Map keyById, Map> valueById) { this.keyById = keyById; this.valueById = valueById; } - public Map getKeyById() { + Map getKeyById() { return keyById; } - public Map> getValueById() { + Map> getValueById() { return valueById; } + + void put(Pair p) { + keyById.put(p.getKey().getId(), p.getKey()); + final ArrayList value = new ArrayList<>(); + value.add(p.getValue()); + valueById.merge(p.getValue().getKeyId(), + value, + (l1, l2) -> { + l1.addAll(l2); + return l1; + }); + } } private static > @@ -165,15 +180,29 @@ BinaryOperator mapMerger(BinaryOperator mergeFunction) { @Test public void collectKeyValueMap() { - final List pairs = generatePairs(10, 100); + final Set pairs = generatePairs(10, 100); // В два прохода - // final Map keyMap1 = pairs.stream()... - - // final Map> valuesMap1 = pairs.stream()... + final Map keyMap1 = pairs.stream() + .collect(toMap(o -> o.getKey().getId(), Pair::getKey, (k1, k2) -> k1)); + + final Map> valuesMap1 = pairs.stream() + .collect(toMap( + o -> o.getValue().getKeyId(), + t -> { + final ArrayList values = new ArrayList<>(); + values.add(t.getValue()); + return values; + }, + (l1, l2) -> { + l1.addAll(l2); + return l1; + } + )); // В каждом Map.Entry id ключа должно совпадать с keyId для каждого значения в списке - // final Map> keyValuesMap1 = valueMap1.entrySet().stream()... + final Map> keyValuesMap1 = valuesMap1.entrySet().stream() + .collect(toMap(o -> keyMap1.get(o.getKey()), Map.Entry::getValue)); // В 1 проход в 2 Map с использованием MapPair и mapMerger final MapPair res2 = pairs.stream() @@ -181,19 +210,29 @@ public void collectKeyValueMap() { @Override public Supplier supplier() { // TODO - throw new UnsupportedOperationException(); + return MapPair::new; } @Override public BiConsumer accumulator() { // TODO add key and value to maps - throw new UnsupportedOperationException(); + return MapPair::put; } @Override public BinaryOperator combiner() { // TODO use mapMerger - throw new UnsupportedOperationException(); + return (mapPair, mapPair2) -> { + BinaryOperator> keyMerger = mapMerger((v1, v2) -> v1); + keyMerger.apply(mapPair.getKeyById(), mapPair2.getKeyById()); + BinaryOperator>> valueMerger = + mapMerger((v1, v2) -> { + v1.addAll(v2); + return v1; + }); + valueMerger.apply(mapPair.getValueById(), mapPair2.getValueById()); + return mapPair; + }; } @Override @@ -212,7 +251,8 @@ public Set characteristics() { final Map keyMap2 = res2.getKeyById(); final Map> valuesMap2 = res2.getValueById(); - // final Map> keyValuesMap2 = valueMap2.entrySet().stream()... + final Map> keyValuesMap2 = valuesMap1.entrySet().stream() + .collect(toMap(o -> keyMap1.get(o.getKey()), Map.Entry::getValue)); // Получение результата сразу: @@ -221,25 +261,54 @@ public Set characteristics() { @Override public Supplier supplier() { // TODO - throw new UnsupportedOperationException(); + return () -> new SubResult(new HashMap<>(), new HashMap<>(), new HashMap<>()); } @Override public BiConsumer accumulator() { // TODO add key to map, then check value.keyId and add it to one of maps - throw new UnsupportedOperationException(); + return (subResult, pair) -> { + subResult.getKnownKeys().put( + pair.getKey().getId(), + pair.getKey()); + final Map> values = + subResult.getValuesWithoutKeys(); + if (values.containsKey(pair.getValue().getKeyId())) + values.get(pair.getValue().getKeyId()) + .add(pair.getValue()); + else { + List value = new ArrayList<>(); + value.add(pair.getValue()); + values.put( + pair.getValue().getKeyId(), + value); + } + }; } @Override public BinaryOperator combiner() { // TODO use mapMerger, then check all valuesWithoutKeys - throw new UnsupportedOperationException(); + return (subResult1, subResult2) -> { + BinaryOperator> keyMerger = mapMerger((v1, v2) -> v1); + keyMerger.apply(subResult1.getKnownKeys(), subResult2.getKnownKeys()); + BinaryOperator>> valueMerger = + mapMerger((v1, v2) -> { + v1.addAll(v2); + return v1; + }); + valueMerger.apply(subResult1.getValuesWithoutKeys(), subResult2.getValuesWithoutKeys()); + return subResult1; + }; } @Override public Function finisher() { // TODO use mapMerger, then check all valuesWithoutKeys - throw new UnsupportedOperationException(); + final Function>> getResult = + subResult -> subResult.getValuesWithoutKeys().entrySet().stream() + .collect(toMap(o -> subResult.getKnownKeys().get(o.getKey()), Map.Entry::getValue)); + return subResult -> new SubResult(getResult.apply(subResult)); } @Override @@ -251,6 +320,9 @@ public Set characteristics() { final Map> keyValuesMap3 = res3.getSubResult(); + assertEquals(keyValuesMap1, keyValuesMap2); + assertEquals(keyValuesMap1, keyValuesMap3); + // compare results } diff --git a/src/test/java/part3/exercise/CollectorCombination.java b/src/test/java/part3/exercise/CollectorCombination.java index 15a42d5..f869a9b 100755 --- a/src/test/java/part3/exercise/CollectorCombination.java +++ b/src/test/java/part3/exercise/CollectorCombination.java @@ -7,6 +7,7 @@ import java.util.List; import java.util.Map; +import java.util.Set; import java.util.function.Function; import java.util.stream.Collector; @@ -46,7 +47,7 @@ public void collectKeyValueMap() { // .collect(new Collector() { // Перепишите решение в слещующем виде: - final List pairs = CollectorsExercise2.generatePairs(10, 100); + final Set pairs = CollectorsExercise2.generatePairs(10, 100); final Pair, Map>> res2 = pairs.stream() .collect(