From 1dc6a2f459e12d2f3b0dd82b451ae9d5a69c3264 Mon Sep 17 00:00:00 2001 From: Jens-Otto Larsen Date: Sat, 24 Sep 2022 17:35:12 +0200 Subject: [PATCH 1/7] Standardcombinators min+max for comparable + equals --- .../fpsak/tidsserie/StandardCombinators.java | 38 ++++++++++- .../LocalDateTimelineExamplesTest.java | 67 +++++++++++++++++++ 2 files changed, 103 insertions(+), 2 deletions(-) diff --git a/src/main/java/no/nav/fpsak/tidsserie/StandardCombinators.java b/src/main/java/no/nav/fpsak/tidsserie/StandardCombinators.java index 85673f9..b03fd96 100644 --- a/src/main/java/no/nav/fpsak/tidsserie/StandardCombinators.java +++ b/src/main/java/no/nav/fpsak/tidsserie/StandardCombinators.java @@ -57,8 +57,7 @@ public static LocalDateSegment> allValues(LocalDateInterval dateInte * Basic combinator som alltid returnerer Boolean.TRUE for angitt interval. Greit å bruke når verdi ikke betyr * noe, kun intervaller. Merk hvilket intervall som benyttes avhenger av {@link JoinStyle} og "includeGaps". Alle som passer får True. */ - public static LocalDateSegment alwaysTrueForMatch( - LocalDateInterval dateInterval, + public static LocalDateSegment alwaysTrueForMatch(LocalDateInterval dateInterval, @SuppressWarnings("unused") LocalDateSegment lhs, // NOSONAR @SuppressWarnings("unused") LocalDateSegment rhs // NOSONAR ) { @@ -78,6 +77,14 @@ public static LocalDateSegment bothValues(LocalDateInterval dateInt } } + /** Basic combinator som returnerer første (Left-Hand Side) verdi hvis begge finnes og er like. */ + public static LocalDateSegment leftIfEqualsRight(LocalDateInterval dateInterval, + LocalDateSegment lhs, + LocalDateSegment rhs) { + return lhs != null && rhs != null && Objects.equals(lhs.getValue(), rhs.getValue()) ? + new LocalDateSegment<>(dateInterval, lhs.getValue()) : null; + } + /** Basic combinator som alltid returnerer verdi fra første (Left-Hand Side) timeline hvis finnes, ellers andre. */ public static LocalDateSegment coalesceLeftHandSide(LocalDateInterval dateInterval, LocalDateSegment lhs, LocalDateSegment rhs) { @@ -137,6 +144,33 @@ public static LocalDateSegment concat(LocalDateInterval dateInterval, return new LocalDateSegment<>(dateInterval, (lv == null ? "" : lv) + (rv == null ? "" : rv)); } + /** + * Basic combinator som tar minste verdi, evt lhs dersom like + */ + public static > LocalDateSegment min(LocalDateInterval dateInterval, + LocalDateSegment lhs, + LocalDateSegment rhs) { + if (lhs != null && rhs != null) { + var least = lhs.getValue().compareTo(rhs.getValue()) <= 0 ? lhs.getValue() : rhs.getValue(); + return new LocalDateSegment<>(dateInterval, least); + } + return lhs == null ? new LocalDateSegment<>(dateInterval, rhs.getValue()) : new LocalDateSegment<>(dateInterval, lhs.getValue()); + } + + /** + * Basic combinator som tar største verdi, evt lhs dersom like + */ + public static > LocalDateSegment max(LocalDateInterval dateInterval, + LocalDateSegment lhs, + LocalDateSegment rhs) { + if (lhs != null && rhs != null) { + var greatest = lhs.getValue().compareTo(rhs.getValue()) >= 0 ? lhs.getValue() : rhs.getValue(); + return new LocalDateSegment<>(dateInterval, greatest); + } + return lhs == null ? new LocalDateSegment<>(dateInterval, rhs.getValue()) : new LocalDateSegment<>(dateInterval, lhs.getValue()); + } + + @SuppressWarnings("unchecked") private static L sum(L lhs, R rhs) { if (lhs == null && rhs == null) { diff --git a/src/test/java/no/nav/fpsak/tidsserie/LocalDateTimelineExamplesTest.java b/src/test/java/no/nav/fpsak/tidsserie/LocalDateTimelineExamplesTest.java index c963b19..edc1a11 100644 --- a/src/test/java/no/nav/fpsak/tidsserie/LocalDateTimelineExamplesTest.java +++ b/src/test/java/no/nav/fpsak/tidsserie/LocalDateTimelineExamplesTest.java @@ -476,6 +476,73 @@ public void eksempel_splitt_av_tidsserie_ved_period_week_1() throws Exception { assertThat(mappedTimeline).isEqualTo(expectedTimeline); } + @Test + public void min_comparable_test() { + + var tidligDato = LocalDate.of(2019,11,15); + var senereDato = LocalDate.of(2020,6,1); + + var timelineA = new LocalDateTimeline<>( + List.of( + toSegment("2019-12-01", "2020-01-02", tidligDato), + toSegment("2020-02-03", "2020-02-16", tidligDato), + toSegment("2020-03-01", "2020-04-30", tidligDato))); + + var timelineB = new LocalDateTimeline<>( + List.of( + toSegment("2019-12-01", "2020-01-02", senereDato), + toSegment("2020-02-03", "2020-02-29", senereDato), + toSegment("2020-04-01", "2020-06-01", senereDato))); + + var timelineBMin = timelineB.combine(timelineA, StandardCombinators::min, JoinStyle.LEFT_JOIN); + + var expectedTimeline = new LocalDateTimeline<>( + List.of( + toSegment("2019-12-01", "2020-01-02", tidligDato), + toSegment("2020-02-03", "2020-02-16", tidligDato), + toSegment("2020-02-17", "2020-02-29", senereDato), + toSegment("2020-04-01", "2020-04-30", tidligDato), + toSegment("2020-05-01", "2020-06-01", senereDato))); + + assertThat(timelineBMin).isEqualTo(expectedTimeline); + } + + @Test + public void likhets_inner_join_test() { + + var tidlig = new ForEqualsTest("type1", LocalDate.of(2019,11,15)); + var senere = new ForEqualsTest("type1", LocalDate.of(2020,6,1)); + var annentype = new ForEqualsTest("type2", LocalDate.of(2020,6,1)); + + var timelineA = new LocalDateTimeline<>( + List.of( + toSegment("2019-12-01", "2020-01-02", tidlig), + toSegment("2020-02-03", "2020-02-16", tidlig), + toSegment("2020-03-01", "2020-04-30", tidlig))); + + var timelineB = new LocalDateTimeline<>( + List.of( + toSegment("2019-12-01", "2020-01-02", tidlig), + toSegment("2020-02-03", "2020-02-29", annentype), + toSegment("2020-04-01", "2020-06-01", senere))); + + var kombinert = timelineB.combine(timelineA, StandardCombinators::leftIfEqualsRight, JoinStyle.INNER_JOIN); + + var expectedTimeline = new LocalDateTimeline<>( + List.of( + toSegment("2019-12-01", "2020-01-02", tidlig), + toSegment("2020-04-01", "2020-04-30", senere))); + + assertThat(kombinert).isEqualTo(expectedTimeline); + } + + private record ForEqualsTest(String type, LocalDate dato) { + @Override + public boolean equals(Object o) { + return this == o || o instanceof ForEqualsTest that && Objects.equals(type, that.type); + } + } + private static LocalDateSegment toSegment(String dt1, String dt2, V val) { return new LocalDateSegment<>(LocalDate.parse(dt1), LocalDate.parse(dt2), val); } From f093f57de45c5df5d9f52e93a7557a960d1c9c0a Mon Sep 17 00:00:00 2001 From: Jens-Otto Larsen Date: Sat, 24 Sep 2022 20:22:44 +0200 Subject: [PATCH 2/7] Concat lists --- .../nav/fpsak/tidsserie/StandardCombinators.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/main/java/no/nav/fpsak/tidsserie/StandardCombinators.java b/src/main/java/no/nav/fpsak/tidsserie/StandardCombinators.java index b03fd96..281d941 100644 --- a/src/main/java/no/nav/fpsak/tidsserie/StandardCombinators.java +++ b/src/main/java/no/nav/fpsak/tidsserie/StandardCombinators.java @@ -9,6 +9,7 @@ import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.stream.Stream; import no.nav.fpsak.tidsserie.LocalDateTimeline.JoinStyle; @@ -170,6 +171,21 @@ public static > LocalDateSegment max(LocalDat return lhs == null ? new LocalDateSegment<>(dateInterval, rhs.getValue()) : new LocalDateSegment<>(dateInterval, lhs.getValue()); } + /** + * Basic combinator som slår sammen Liste-verdier til en liste + */ + public static LocalDateSegment> concatToList(LocalDateInterval dateInterval, + LocalDateSegment> lhs, + LocalDateSegment> rhs) { + if (lhs != null && rhs != null) { + return new LocalDateSegment<>(dateInterval, Stream.concat(lhs.getValue().stream(), rhs.getValue().stream()).toList()); + } else if (lhs == null && rhs == null) { + return null; + } + return lhs == null ? new LocalDateSegment<>(dateInterval, rhs.getValue()) : new LocalDateSegment<>(dateInterval, lhs.getValue()); + } + + @SuppressWarnings("unchecked") private static L sum(L lhs, R rhs) { From 379dd152a7318f4b273f285bfd18d0034b2ce159 Mon Sep 17 00:00:00 2001 From: Jens-Otto Larsen Date: Sat, 24 Sep 2022 20:23:35 +0200 Subject: [PATCH 3/7] Concat lists fix name --- .../java/no/nav/fpsak/tidsserie/StandardCombinators.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/no/nav/fpsak/tidsserie/StandardCombinators.java b/src/main/java/no/nav/fpsak/tidsserie/StandardCombinators.java index 281d941..6b87763 100644 --- a/src/main/java/no/nav/fpsak/tidsserie/StandardCombinators.java +++ b/src/main/java/no/nav/fpsak/tidsserie/StandardCombinators.java @@ -174,9 +174,9 @@ public static > LocalDateSegment max(LocalDat /** * Basic combinator som slår sammen Liste-verdier til en liste */ - public static LocalDateSegment> concatToList(LocalDateInterval dateInterval, - LocalDateSegment> lhs, - LocalDateSegment> rhs) { + public static LocalDateSegment> concatLists(LocalDateInterval dateInterval, + LocalDateSegment> lhs, + LocalDateSegment> rhs) { if (lhs != null && rhs != null) { return new LocalDateSegment<>(dateInterval, Stream.concat(lhs.getValue().stream(), rhs.getValue().stream()).toList()); } else if (lhs == null && rhs == null) { From 9965297a5119888fdb54849884aea96d04995894 Mon Sep 17 00:00:00 2001 From: Jens-Otto Larsen Date: Mon, 26 Sep 2022 13:34:11 +0200 Subject: [PATCH 4/7] Fjerner equalsfilter --- .../fpsak/tidsserie/StandardCombinators.java | 8 ----- .../LocalDateTimelineExamplesTest.java | 36 ------------------- 2 files changed, 44 deletions(-) diff --git a/src/main/java/no/nav/fpsak/tidsserie/StandardCombinators.java b/src/main/java/no/nav/fpsak/tidsserie/StandardCombinators.java index 6b87763..b2c064a 100644 --- a/src/main/java/no/nav/fpsak/tidsserie/StandardCombinators.java +++ b/src/main/java/no/nav/fpsak/tidsserie/StandardCombinators.java @@ -78,14 +78,6 @@ public static LocalDateSegment bothValues(LocalDateInterval dateInt } } - /** Basic combinator som returnerer første (Left-Hand Side) verdi hvis begge finnes og er like. */ - public static LocalDateSegment leftIfEqualsRight(LocalDateInterval dateInterval, - LocalDateSegment lhs, - LocalDateSegment rhs) { - return lhs != null && rhs != null && Objects.equals(lhs.getValue(), rhs.getValue()) ? - new LocalDateSegment<>(dateInterval, lhs.getValue()) : null; - } - /** Basic combinator som alltid returnerer verdi fra første (Left-Hand Side) timeline hvis finnes, ellers andre. */ public static LocalDateSegment coalesceLeftHandSide(LocalDateInterval dateInterval, LocalDateSegment lhs, LocalDateSegment rhs) { diff --git a/src/test/java/no/nav/fpsak/tidsserie/LocalDateTimelineExamplesTest.java b/src/test/java/no/nav/fpsak/tidsserie/LocalDateTimelineExamplesTest.java index edc1a11..23ccf99 100644 --- a/src/test/java/no/nav/fpsak/tidsserie/LocalDateTimelineExamplesTest.java +++ b/src/test/java/no/nav/fpsak/tidsserie/LocalDateTimelineExamplesTest.java @@ -507,42 +507,6 @@ public void min_comparable_test() { assertThat(timelineBMin).isEqualTo(expectedTimeline); } - @Test - public void likhets_inner_join_test() { - - var tidlig = new ForEqualsTest("type1", LocalDate.of(2019,11,15)); - var senere = new ForEqualsTest("type1", LocalDate.of(2020,6,1)); - var annentype = new ForEqualsTest("type2", LocalDate.of(2020,6,1)); - - var timelineA = new LocalDateTimeline<>( - List.of( - toSegment("2019-12-01", "2020-01-02", tidlig), - toSegment("2020-02-03", "2020-02-16", tidlig), - toSegment("2020-03-01", "2020-04-30", tidlig))); - - var timelineB = new LocalDateTimeline<>( - List.of( - toSegment("2019-12-01", "2020-01-02", tidlig), - toSegment("2020-02-03", "2020-02-29", annentype), - toSegment("2020-04-01", "2020-06-01", senere))); - - var kombinert = timelineB.combine(timelineA, StandardCombinators::leftIfEqualsRight, JoinStyle.INNER_JOIN); - - var expectedTimeline = new LocalDateTimeline<>( - List.of( - toSegment("2019-12-01", "2020-01-02", tidlig), - toSegment("2020-04-01", "2020-04-30", senere))); - - assertThat(kombinert).isEqualTo(expectedTimeline); - } - - private record ForEqualsTest(String type, LocalDate dato) { - @Override - public boolean equals(Object o) { - return this == o || o instanceof ForEqualsTest that && Objects.equals(type, that.type); - } - } - private static LocalDateSegment toSegment(String dt1, String dt2, V val) { return new LocalDateSegment<>(LocalDate.parse(dt1), LocalDate.parse(dt2), val); } From 7a56490606443d48ba6c39a489ac3c8a7b8e4191 Mon Sep 17 00:00:00 2001 From: Jens-Otto Larsen Date: Mon, 26 Sep 2022 14:50:17 +0200 Subject: [PATCH 5/7] Add set union, intersection and difference --- .../fpsak/tidsserie/StandardCombinators.java | 49 +++++++++++++++++++ .../LocalDateTimelineExamplesTest.java | 28 +++++++++++ 2 files changed, 77 insertions(+) diff --git a/src/main/java/no/nav/fpsak/tidsserie/StandardCombinators.java b/src/main/java/no/nav/fpsak/tidsserie/StandardCombinators.java index b2c064a..9af51c2 100644 --- a/src/main/java/no/nav/fpsak/tidsserie/StandardCombinators.java +++ b/src/main/java/no/nav/fpsak/tidsserie/StandardCombinators.java @@ -6,9 +6,12 @@ import java.util.Arrays; import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; import java.util.stream.Stream; import no.nav.fpsak.tidsserie.LocalDateTimeline.JoinStyle; @@ -177,6 +180,52 @@ public static LocalDateSegment> concatLists(LocalDateInterval dateIn return lhs == null ? new LocalDateSegment<>(dateInterval, rhs.getValue()) : new LocalDateSegment<>(dateInterval, lhs.getValue()); } + /** + * Basic combinator som slår sammen to Sets vha Union + */ + public static LocalDateSegment> union(LocalDateInterval dateInterval, + LocalDateSegment> lhs, + LocalDateSegment> rhs) { + if (lhs != null && rhs != null) { + var union = new HashSet<>(lhs.getValue()); + union.addAll(rhs.getValue()); + return new LocalDateSegment<>(dateInterval, union); + } else if (lhs == null && rhs == null) { + return null; + } + return lhs == null ? new LocalDateSegment<>(dateInterval, rhs.getValue()) : new LocalDateSegment<>(dateInterval, lhs.getValue()); + } + + /** + * Basic combinator som slår sammen to Sets vha Intersection + */ + public static LocalDateSegment> intersection(LocalDateInterval dateInterval, + LocalDateSegment> lhs, + LocalDateSegment> rhs) { + if (lhs != null && rhs != null) { + var intersection = lhs.getValue().stream().filter(v -> rhs.getValue().contains(v)).collect(Collectors.toCollection(HashSet::new)); + return new LocalDateSegment<>(dateInterval, intersection); + } else if (lhs == null && rhs == null) { + return null; + } + return lhs == null ? new LocalDateSegment<>(dateInterval, rhs.getValue()) : new LocalDateSegment<>(dateInterval, lhs.getValue()); + } + + /** + * Basic combinator som slår sammen to Sets vha Intersection + */ + public static LocalDateSegment> difference(LocalDateInterval dateInterval, + LocalDateSegment> lhs, + LocalDateSegment> rhs) { + if (lhs != null && rhs != null) { + var intersection = lhs.getValue().stream().filter(v -> !rhs.getValue().contains(v)).collect(Collectors.toCollection(HashSet::new)); + return new LocalDateSegment<>(dateInterval, intersection); + } else if (lhs == null && rhs == null) { + return null; + } + return lhs == null ? new LocalDateSegment<>(dateInterval, rhs.getValue()) : new LocalDateSegment<>(dateInterval, lhs.getValue()); + } + @SuppressWarnings("unchecked") diff --git a/src/test/java/no/nav/fpsak/tidsserie/LocalDateTimelineExamplesTest.java b/src/test/java/no/nav/fpsak/tidsserie/LocalDateTimelineExamplesTest.java index 23ccf99..dd67d51 100644 --- a/src/test/java/no/nav/fpsak/tidsserie/LocalDateTimelineExamplesTest.java +++ b/src/test/java/no/nav/fpsak/tidsserie/LocalDateTimelineExamplesTest.java @@ -10,6 +10,7 @@ import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Set; import java.util.function.Function; import java.util.stream.Collectors; @@ -507,6 +508,33 @@ public void min_comparable_test() { assertThat(timelineBMin).isEqualTo(expectedTimeline); } + @Test + public void set_difference() { + + var timelineA = new LocalDateTimeline>( + List.of( + toSegment("2019-12-01", "2020-01-02", Set.of(1,2,3)), + toSegment("2020-02-03", "2020-02-16", Set.of(1,2,3,4,5,6)), + toSegment("2020-03-01", "2020-04-30", Set.of(1,2,3,4,5,6,7,8,9)))); + + var timelineB = new LocalDateTimeline>( + List.of( + toSegment("2019-12-01", "2020-01-02", Set.of()), + toSegment("2020-02-03", "2020-02-29", Set.of(1,2,3)), + toSegment("2020-04-01", "2020-06-01", Set.of(1,2,3,4,5,6)))); + + var timelineBMin = timelineA.combine(timelineB, StandardCombinators::difference, JoinStyle.LEFT_JOIN); + + var expectedTimeline = new LocalDateTimeline>( + List.of( + toSegment("2019-12-01", "2020-01-02", Set.of(1,2,3)), + toSegment("2020-02-03", "2020-02-16", Set.of(4,5,6)), + toSegment("2020-03-01", "2020-03-31", Set.of(1,2,3,4,5,6,7,8,9)), + toSegment("2020-04-01", "2020-04-30", Set.of(7,8,9)))); + + assertThat(timelineBMin).isEqualTo(expectedTimeline); + } + private static LocalDateSegment toSegment(String dt1, String dt2, V val) { return new LocalDateSegment<>(LocalDate.parse(dt1), LocalDate.parse(dt2), val); } From 7ed7830fbf20f235e2d26d12caa23401d66c80e1 Mon Sep 17 00:00:00 2001 From: Jens-Otto Larsen Date: Mon, 26 Sep 2022 14:50:49 +0200 Subject: [PATCH 6/7] Comments on difference --- src/main/java/no/nav/fpsak/tidsserie/StandardCombinators.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/no/nav/fpsak/tidsserie/StandardCombinators.java b/src/main/java/no/nav/fpsak/tidsserie/StandardCombinators.java index 9af51c2..8f8fcf6 100644 --- a/src/main/java/no/nav/fpsak/tidsserie/StandardCombinators.java +++ b/src/main/java/no/nav/fpsak/tidsserie/StandardCombinators.java @@ -212,7 +212,7 @@ public static LocalDateSegment> intersection(LocalDateInterval dateIn } /** - * Basic combinator som slår sammen to Sets vha Intersection + * Basic combinator som slår sammen to Sets vha Difference (A-B) */ public static LocalDateSegment> difference(LocalDateInterval dateInterval, LocalDateSegment> lhs, From 32002bda3c2ab5c4ce7f0b9703bcb81ab0bf48c7 Mon Sep 17 00:00:00 2001 From: Jens-Otto Larsen Date: Mon, 26 Sep 2022 15:10:16 +0200 Subject: [PATCH 7/7] Mer navngivning --- .../java/no/nav/fpsak/tidsserie/StandardCombinators.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/no/nav/fpsak/tidsserie/StandardCombinators.java b/src/main/java/no/nav/fpsak/tidsserie/StandardCombinators.java index 8f8fcf6..ca90a7e 100644 --- a/src/main/java/no/nav/fpsak/tidsserie/StandardCombinators.java +++ b/src/main/java/no/nav/fpsak/tidsserie/StandardCombinators.java @@ -212,14 +212,14 @@ public static LocalDateSegment> intersection(LocalDateInterval dateIn } /** - * Basic combinator som slår sammen to Sets vha Difference (A-B) + * Basic combinator som slår sammen to Sets vha Difference (LHS-RHS) */ public static LocalDateSegment> difference(LocalDateInterval dateInterval, LocalDateSegment> lhs, LocalDateSegment> rhs) { if (lhs != null && rhs != null) { - var intersection = lhs.getValue().stream().filter(v -> !rhs.getValue().contains(v)).collect(Collectors.toCollection(HashSet::new)); - return new LocalDateSegment<>(dateInterval, intersection); + var difference = lhs.getValue().stream().filter(v -> !rhs.getValue().contains(v)).collect(Collectors.toCollection(HashSet::new)); + return new LocalDateSegment<>(dateInterval, difference); } else if (lhs == null && rhs == null) { return null; }