diff --git a/src/main/java/lambda/data/Employee.java b/src/main/java/lambda/data/Employee.java new file mode 100644 index 0000000..df2b8c3 --- /dev/null +++ b/src/main/java/lambda/data/Employee.java @@ -0,0 +1,49 @@ +package lambda.data; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +public class Employee { + + private final Person person; + private final List jobHistory; + + public Employee(Person person, List jobHistory) { + this.person = person; + this.jobHistory = new ArrayList<>(jobHistory); + } + + public Person getPerson() { + return person; + } + + public List getJobHistory() { + return new ArrayList<>(jobHistory); + } + + @Override + public String toString() { + return "Employee@" + hashCode() + " {" + + "person=" + person + ", " + + "jobHistory=" + jobHistory + "}"; + } + + @Override + public boolean equals(Object object) { + if (this == object) { + return true; + } + if (object == null || getClass() != object.getClass()) { + return false; + } + Employee employee = (Employee) object; + return Objects.equals(person, employee.person) + && Objects.equals(jobHistory, employee.jobHistory); + } + + @Override + public int hashCode() { + return Objects.hash(person, jobHistory); + } +} diff --git a/src/main/java/lambda/data/JobHistoryEntry.java b/src/main/java/lambda/data/JobHistoryEntry.java new file mode 100644 index 0000000..e4dc359 --- /dev/null +++ b/src/main/java/lambda/data/JobHistoryEntry.java @@ -0,0 +1,55 @@ +package lambda.data; + +import java.util.Objects; + +public class JobHistoryEntry { + + private final String employer; + private final String position; + private final int duration; + + public JobHistoryEntry(int duration, String position, String employer) { + this.duration = duration; + this.position = position; + this.employer = employer; + } + + public int getDuration() { + return duration; + } + + public String getPosition() { + return position; + } + + public String getEmployer() { + return employer; + } + + @Override + public String toString() { + return "JobHistoryEntry@" + hashCode() + ": {" + + "duration=" + duration + ", " + + "position='" + position + "\', " + + "employer='" + employer + "\'}"; + } + + @Override + public boolean equals(Object other) { + if (this == other) { + return true; + } + if (other == null || getClass() != other.getClass()) { + return false; + } + JobHistoryEntry entry = (JobHistoryEntry) other; + return duration == entry.duration + && Objects.equals(position, entry.position) + && Objects.equals(employer, entry.employer); + } + + @Override + public int hashCode() { + return Objects.hash(duration, position, employer); + } +} diff --git a/src/main/java/lambda/data/Person.java b/src/main/java/lambda/data/Person.java index 773efac..19fe667 100644 --- a/src/main/java/lambda/data/Person.java +++ b/src/main/java/lambda/data/Person.java @@ -1,8 +1,11 @@ package lambda.data; +import org.jetbrains.annotations.NotNull; + +import java.io.Serializable; import java.util.Objects; -public class Person { +public class Person implements Serializable { private final String firstName; private final String lastName; @@ -14,12 +17,14 @@ public Person(String firstName, String lastName, int age) { this.age = age; } - public String getFirstName(Person this) { - return firstName; + public Person() { + firstName = "default"; + lastName = "default"; + age = -1; } - public String getLastName() { - return lastName; + public String getLastName(Person this) { + return this.lastName; } public int getAge() { diff --git a/src/test/java/streams/part2/exercise/Exercise2.java b/src/test/java/streams/part2/exercise/Exercise2.java new file mode 100644 index 0000000..b0beaff --- /dev/null +++ b/src/test/java/streams/part2/exercise/Exercise2.java @@ -0,0 +1,235 @@ +package streams.part2.exercise; + +import javafx.util.Pair; +import lambda.data.Employee; +import lambda.data.JobHistoryEntry; +import lambda.data.Person; +import org.junit.jupiter.api.Test; + +import java.util.*; + +import static java.util.stream.Collectors.*; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.*; + +@SuppressWarnings("ConstantConditions") +class Exercise2 { + + private static List getEmployees() { + return Arrays.asList( + new Employee( + new Person("Иван", "Мельников", 30), + Arrays.asList( + new JobHistoryEntry(2, "dev", "EPAM"), + new JobHistoryEntry(1, "dev", "google") + )), + new Employee( + new Person("Александр", "Дементьев", 28), + Arrays.asList( + new JobHistoryEntry(1, "tester", "EPAM"), + new JobHistoryEntry(2, "dev", "EPAM"), + new JobHistoryEntry(2, "dev", "google") + )), + new Employee( + new Person("Дмитрий", "Осинов", 40), + Arrays.asList( + new JobHistoryEntry(3, "QA", "yandex"), + new JobHistoryEntry(1, "QA", "mail.ru"), + new JobHistoryEntry(1, "dev", "mail.ru") + )), + new Employee( + new Person("Анна", "Светличная", 21), + Collections.singletonList( + new JobHistoryEntry(1, "tester", "T-Systems") + )), + new Employee( + new Person("Игорь", "Толмачёв", 50), + Arrays.asList( + new JobHistoryEntry(5, "tester", "EPAM"), + new JobHistoryEntry(6, "QA", "EPAM") + )), + new Employee( + new Person("Иван", "Александров", 33), + Arrays.asList( + new JobHistoryEntry(2, "QA", "T-Systems"), + new JobHistoryEntry(3, "QA", "EPAM"), + new JobHistoryEntry(1, "dev", "EPAM") + )) + ); + } + + private static Map prepareExpected(List employees) { + Map expected = new HashMap<>(); + expected.put("dev", employees.get(0).getPerson()); + expected.put("tester", employees.get(4).getPerson()); + expected.put("QA", employees.get(4).getPerson()); + return expected; + } + + /** + * Преобразовать список сотрудников в отображение [компания -> множество людей, когда-либо работавших в этой компании]. + *

+ * Входные данные: + * [ + * { + * {Иван Мельников 30}, + * [ + * {2, dev, "EPAM"}, + * {1, dev, "google"} + * ] + * }, + * { + * {Александр Дементьев 28}, + * [ + * {2, tester, "EPAM"}, + * {1, dev, "EPAM"}, + * {1, dev, "google"} + * ] + * }, + * { + * {Дмитрий Осинов 40}, + * [ + * {3, QA, "yandex"}, + * {1, QA, "EPAM"}, + * {1, dev, "mail.ru"} + * ] + * }, + * { + * {Анна Светличная 21}, + * [ + * {1, tester, "T-Systems"} + * ] + * } + * ] + *

+ * Выходные данные: + * [ + * "EPAM" -> [ + * {Иван Мельников 30}, + * {Александр Дементьев 28}, + * {Дмитрий Осинов 40} + * ], + * "google" -> [ + * {Иван Мельников 30}, + * {Александр Дементьев 28} + * ], + * "yandex" -> [ {Дмитрий Осинов 40} ] + * "mail.ru" -> [ {Дмитрий Осинов 40} ] + * "T-Systems" -> [ {Анна Светличная 21} ] + * ] + */ + + @Test + void employersStuffList() { + List employees = getEmployees(); + + Map> result = employees.stream() + .flatMap(employee -> { + Person person = employee.getPerson(); + return employee.getJobHistory().stream().map(job -> new Pair<>(job.getEmployer(), person)); + }) + .collect(groupingBy(Pair::getKey, mapping(Pair::getValue, toSet()))); + + assertThat(result, hasEntry((is("yandex")), contains(employees.get(2).getPerson()))); + assertThat(result, hasEntry((is("mail.ru")), contains(employees.get(2).getPerson()))); + assertThat(result, hasEntry((is("google")), containsInAnyOrder(employees.get(0).getPerson(), employees.get(1).getPerson()))); + assertThat(result, hasEntry((is("T-Systems")), containsInAnyOrder(employees.get(3).getPerson(), employees.get(5).getPerson()))); + assertThat(result, hasEntry((is("EPAM")), containsInAnyOrder( + employees.get(0).getPerson(), + employees.get(1).getPerson(), + employees.get(4).getPerson(), + employees.get(5).getPerson())) + ); + } + + /** + * Преобразовать список сотрудников в отображение [компания -> множество людей, начавших свою карьеру в этой компании]. + *

+ * Пример. + *

+ * Входные данные: + * [ + * { + * {Иван Мельников 30}, + * [ + * {2, dev, "EPAM"}, + * {1, dev, "google"} + * ] + * }, + * { + * {Александр Дементьев 28}, + * [ + * {2, tester, "EPAM"}, + * {1, dev, "EPAM"}, + * {1, dev, "google"} + * ] + * }, + * { + * {Дмитрий Осинов 40}, + * [ + * {3, QA, "yandex"}, + * {1, QA, "EPAM"}, + * {1, dev, "mail.ru"} + * ] + * }, + * { + * {Анна Светличная 21}, + * [ + * {1, tester, "T-Systems"} + * ] + * } + * ] + *

+ * Выходные данные: + * [ + * "EPAM" -> [ + * {Иван Мельников 30}, + * {Александр Дементьев 28} + * ], + * "yandex" -> [ {Дмитрий Осинов 40} ] + * "T-Systems" -> [ {Анна Светличная 21} ] + * ] + */ + + @Test + void indexByFirstEmployer() { + List employees = getEmployees(); + + Map> result = employees.stream() + .map(employee -> new Pair<>(employee.getJobHistory().get(0).getEmployer(), employee.getPerson())) + .collect(groupingBy(Pair::getKey, mapping(Pair::getValue, toSet()))); + + assertThat(result, hasEntry(is("yandex"), contains(employees.get(2).getPerson()))); + assertThat(result, hasEntry(is("T-Systems"), containsInAnyOrder(employees.get(3).getPerson(), employees.get(5).getPerson()))); + assertThat(result, hasEntry(is("EPAM"), containsInAnyOrder( + employees.get(0).getPerson(), + employees.get(1).getPerson(), + employees.get(4).getPerson() + ))); + } + + /** + * Преобразовать список сотрудников в отображение [компания -> сотрудник, суммарно проработавший в ней наибольшее время]. + * Гарантируется, что такой сотрудник будет один. + */ + @Test + void greatestExperiencePerEmployer() { + List employees = getEmployees(); + + Map collect = employees.stream() + .flatMap(employee -> { + Person person = employee.getPerson(); + return employee.getJobHistory().stream().map(job -> new Pair<>(job, person)); + }) + .collect(groupingBy(pair -> pair.getKey().getEmployer(), + collectingAndThen(collectingAndThen(toMap(Pair::getValue, x -> x.getKey().getDuration(), (oldValue, newValue) -> oldValue + newValue), + entry -> entry.entrySet().stream().max(Comparator.comparing(Map.Entry::getValue))), entry -> entry.get().getKey()))); + + assertThat(collect, hasEntry("EPAM", employees.get(4).getPerson())); + assertThat(collect, hasEntry("google", employees.get(1).getPerson())); + assertThat(collect, hasEntry("yandex", employees.get(2).getPerson())); + assertThat(collect, hasEntry("mail.ru", employees.get(2).getPerson())); + assertThat(collect, hasEntry("T-Systems", employees.get(5).getPerson())); + } + +}