From cd6fa70440c673f1d1d092eccd6cc714704a98cb Mon Sep 17 00:00:00 2001 From: cn337131 <141730190+cn337131@users.noreply.github.com> Date: Wed, 15 Jan 2025 10:23:31 +0000 Subject: [PATCH 1/4] add new iterable merge binary operator and varargs to chainedItr --- .../impl/binaryoperator/IterableMerge.java | 38 +++++ .../koryphe/iterable/ChainedIterator.java | 9 +- .../binaryoperator/IterableMergeTest.java | 132 ++++++++++++++++++ 3 files changed, 178 insertions(+), 1 deletion(-) create mode 100644 core/src/main/java/uk/gov/gchq/koryphe/impl/binaryoperator/IterableMerge.java create mode 100644 core/src/test/java/uk/gov/gchq/koryphe/impl/binaryoperator/IterableMergeTest.java diff --git a/core/src/main/java/uk/gov/gchq/koryphe/impl/binaryoperator/IterableMerge.java b/core/src/main/java/uk/gov/gchq/koryphe/impl/binaryoperator/IterableMerge.java new file mode 100644 index 00000000..9f414669 --- /dev/null +++ b/core/src/main/java/uk/gov/gchq/koryphe/impl/binaryoperator/IterableMerge.java @@ -0,0 +1,38 @@ +/* + * Copyright 2025 Crown Copyright + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package uk.gov.gchq.koryphe.impl.binaryoperator; + +import uk.gov.gchq.koryphe.Since; +import uk.gov.gchq.koryphe.Summary; +import uk.gov.gchq.koryphe.binaryoperator.KorypheBinaryOperator; +import uk.gov.gchq.koryphe.util.IterableUtil; + +import java.util.Arrays; + +/** + * An IterableMerge is a {@link KorypheBinaryOperator} that takes two + * {@link java.lang.Iterable}s and merges them together. + */ +@Since("2.6.0") +@Summary("Merges two iterables together.") +public class IterableMerge extends KorypheBinaryOperator> { + + @Override + protected Iterable _apply(Iterable a, Iterable b) { + return IterableUtil.concat(Arrays.asList(a, b)); + } +} diff --git a/core/src/main/java/uk/gov/gchq/koryphe/iterable/ChainedIterator.java b/core/src/main/java/uk/gov/gchq/koryphe/iterable/ChainedIterator.java index 2c38130d..71a57cb1 100644 --- a/core/src/main/java/uk/gov/gchq/koryphe/iterable/ChainedIterator.java +++ b/core/src/main/java/uk/gov/gchq/koryphe/iterable/ChainedIterator.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Crown Copyright + * Copyright 2025 Crown Copyright * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,9 +16,12 @@ package uk.gov.gchq.koryphe.iterable; +import org.apache.commons.lang3.ArrayUtils; + import uk.gov.gchq.koryphe.util.CloseableUtil; import java.io.Closeable; +import java.util.Arrays; import java.util.Collections; import java.util.Iterator; @@ -31,6 +34,10 @@ public class ChainedIterator implements Closeable, Iterator { private final Iterator> iterablesIterator; private Iterator currentIterator = Collections.emptyIterator(); + public ChainedIterator(final Iterable... iterators) { + this(ArrayUtils.isEmpty(iterators) ? null : Arrays.asList(iterators).iterator()); + } + public ChainedIterator(final Iterator> iterablesIterator) { if (null == iterablesIterator) { throw new IllegalArgumentException("iterables are required"); diff --git a/core/src/test/java/uk/gov/gchq/koryphe/impl/binaryoperator/IterableMergeTest.java b/core/src/test/java/uk/gov/gchq/koryphe/impl/binaryoperator/IterableMergeTest.java new file mode 100644 index 00000000..bebb0fce --- /dev/null +++ b/core/src/test/java/uk/gov/gchq/koryphe/impl/binaryoperator/IterableMergeTest.java @@ -0,0 +1,132 @@ +/* + * Copyright 2025 Crown Copyright + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package uk.gov.gchq.koryphe.impl.binaryoperator; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.Test; + +import com.google.common.collect.Lists; + +import uk.gov.gchq.koryphe.binaryoperator.BinaryOperatorTest; +import uk.gov.gchq.koryphe.iterable.ChainedIterable; +import uk.gov.gchq.koryphe.util.JsonSerialiser; + +import java.io.IOException; +import java.util.HashSet; +import java.util.List; +import java.util.TreeSet; + +class IterableMergeTest extends BinaryOperatorTest { + + @Test + public void shouldJsonSerialiseAndDeserialise() throws IOException { + // Given + final IterableMerge merger = new IterableMerge<>(); + + // When + final String json = JsonSerialiser.serialise(merger); + + // Then + JsonSerialiser.assertEquals( + String.format("{%n" + + " \"class\" : \"uk.gov.gchq.koryphe.impl.binaryoperator.IterableMerge\"%n" + + "}"), + json); + + // When + final IterableMerge deserialisedMerger = JsonSerialiser.deserialise(json, IterableMerge.class); + + // Then + assertThat(deserialisedMerger).isNotNull(); + } + + @Test + void shouldMergeArrays() { + // Given + final IterableMerge merger = new IterableMerge<>(); + final List itr1 = Lists.newArrayList(1, 2, 3, 4); + final List itr2 = Lists.newArrayList(5, 6); + + // When + final Iterable result = merger.apply(itr1, itr2); + + // Then + assertThat(result) + .isInstanceOf(ChainedIterable.class) + .containsExactly(1, 2, 3, 4, 5, 6); + } + + @Test + void shouldMergeHashSets() { + // Given + final HashSet hashSet1 = new HashSet<>(); + hashSet1.add(1); + + final HashSet hashSet2 = new HashSet<>(); + hashSet2.add(2); + hashSet2.add(3); + + IterableMerge merger = new IterableMerge<>(); + final Iterable result = merger.apply(hashSet1, hashSet2); + + assertThat(result).containsExactly(1, 2, 3); + } + + @Test + void shouldMergeTreeSets() { + // Given + final TreeSet treeSet1 = new TreeSet<>(); + treeSet1.add("string1"); + + final TreeSet treeSet2 = new TreeSet<>(); + treeSet2.add("string3"); + treeSet2.add("string2"); + + final IterableMerge merger = new IterableMerge<>(); + + // When + final Iterable result = merger.apply(treeSet1, treeSet2); + + // Then + assertThat(result).containsExactly("string1", "string2", "string3"); + } + + @Test + void shouldHandleNullElementsOfIterable() { + // Given + final IterableMerge merger = new IterableMerge<>(); + final List itr1 = Lists.newArrayList(1, 2, null, 4); + final List itr2 = Lists.newArrayList(null, 6); + + // When + final Iterable results = merger.apply(itr1, itr2); + + // Then + assertThat(results).containsExactly(1, 2, null, 4, null, 6); + } + + @Override + protected IterableMerge getInstance() { + return new IterableMerge<>(); + } + + @Override + protected Iterable getDifferentInstancesOrNull() { + return null; + } +} From 3426e57556084b57fe0ebd30bb5839b4e88024d2 Mon Sep 17 00:00:00 2001 From: cn337131 <141730190+cn337131@users.noreply.github.com> Date: Wed, 15 Jan 2025 12:16:20 +0000 Subject: [PATCH 2/4] checkstyle --- .../uk/gov/gchq/koryphe/impl/binaryoperator/IterableMerge.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/uk/gov/gchq/koryphe/impl/binaryoperator/IterableMerge.java b/core/src/main/java/uk/gov/gchq/koryphe/impl/binaryoperator/IterableMerge.java index 9f414669..8e3a3d05 100644 --- a/core/src/main/java/uk/gov/gchq/koryphe/impl/binaryoperator/IterableMerge.java +++ b/core/src/main/java/uk/gov/gchq/koryphe/impl/binaryoperator/IterableMerge.java @@ -32,7 +32,7 @@ public class IterableMerge extends KorypheBinaryOperator> { @Override - protected Iterable _apply(Iterable a, Iterable b) { + protected Iterable _apply(final Iterable a, final Iterable b) { return IterableUtil.concat(Arrays.asList(a, b)); } } From 533892267873548e92854eb26478074faad0afb1 Mon Sep 17 00:00:00 2001 From: cn337131 <141730190+cn337131@users.noreply.github.com> Date: Wed, 15 Jan 2025 16:21:10 +0000 Subject: [PATCH 3/4] address comments --- .../java/uk/gov/gchq/koryphe/iterable/ChainedIterator.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/core/src/main/java/uk/gov/gchq/koryphe/iterable/ChainedIterator.java b/core/src/main/java/uk/gov/gchq/koryphe/iterable/ChainedIterator.java index 71a57cb1..5eb1c6b6 100644 --- a/core/src/main/java/uk/gov/gchq/koryphe/iterable/ChainedIterator.java +++ b/core/src/main/java/uk/gov/gchq/koryphe/iterable/ChainedIterator.java @@ -16,8 +16,6 @@ package uk.gov.gchq.koryphe.iterable; -import org.apache.commons.lang3.ArrayUtils; - import uk.gov.gchq.koryphe.util.CloseableUtil; import java.io.Closeable; @@ -35,7 +33,7 @@ public class ChainedIterator implements Closeable, Iterator { private Iterator currentIterator = Collections.emptyIterator(); public ChainedIterator(final Iterable... iterators) { - this(ArrayUtils.isEmpty(iterators) ? null : Arrays.asList(iterators).iterator()); + this((iterators== null || iterators.length == 0) ? null : Arrays.asList(iterators).iterator()); } public ChainedIterator(final Iterator> iterablesIterator) { From 06d2657e730bbb060a67894ed30756725ee8a2d4 Mon Sep 17 00:00:00 2001 From: cn337131 <141730190+cn337131@users.noreply.github.com> Date: Wed, 15 Jan 2025 16:22:35 +0000 Subject: [PATCH 4/4] checkstyle --- .../main/java/uk/gov/gchq/koryphe/iterable/ChainedIterator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/uk/gov/gchq/koryphe/iterable/ChainedIterator.java b/core/src/main/java/uk/gov/gchq/koryphe/iterable/ChainedIterator.java index 5eb1c6b6..e51edac4 100644 --- a/core/src/main/java/uk/gov/gchq/koryphe/iterable/ChainedIterator.java +++ b/core/src/main/java/uk/gov/gchq/koryphe/iterable/ChainedIterator.java @@ -33,7 +33,7 @@ public class ChainedIterator implements Closeable, Iterator { private Iterator currentIterator = Collections.emptyIterator(); public ChainedIterator(final Iterable... iterators) { - this((iterators== null || iterators.length == 0) ? null : Arrays.asList(iterators).iterator()); + this((iterators == null || iterators.length == 0) ? null : Arrays.asList(iterators).iterator()); } public ChainedIterator(final Iterator> iterablesIterator) {