Skip to content

Commit

Permalink
Gh-321: Add ChainedIterator varargs constructor and IterableMerge bin…
Browse files Browse the repository at this point in the history
…ary operator (#328)

* add new iterable merge binary operator and varargs to chainedItr

* checkstyle

* address comments

* checkstyle
  • Loading branch information
cn337131 authored Jan 27, 2025
1 parent bc76769 commit f2dead6
Show file tree
Hide file tree
Showing 3 changed files with 176 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -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 <code>IterableMerge</code> 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<T> extends KorypheBinaryOperator<Iterable<T>> {

@Override
protected Iterable<T> _apply(final Iterable<T> a, final Iterable<T> b) {
return IterableUtil.concat(Arrays.asList(a, b));
}
}
Original file line number Diff line number Diff line change
@@ -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.
Expand All @@ -19,6 +19,7 @@
import uk.gov.gchq.koryphe.util.CloseableUtil;

import java.io.Closeable;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;

Expand All @@ -31,6 +32,10 @@ public class ChainedIterator<T> implements Closeable, Iterator<T> {
private final Iterator<? extends Iterable<? extends T>> iterablesIterator;
private Iterator<? extends T> currentIterator = Collections.emptyIterator();

public ChainedIterator(final Iterable<? extends T>... iterators) {
this((iterators == null || iterators.length == 0) ? null : Arrays.asList(iterators).iterator());
}

public ChainedIterator(final Iterator<? extends Iterable<? extends T>> iterablesIterator) {
if (null == iterablesIterator) {
throw new IllegalArgumentException("iterables are required");
Expand Down
Original file line number Diff line number Diff line change
@@ -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<IterableMerge> {

@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<Integer> merger = new IterableMerge<>();
final List<Integer> itr1 = Lists.newArrayList(1, 2, 3, 4);
final List<Integer> itr2 = Lists.newArrayList(5, 6);

// When
final Iterable<Integer> result = merger.apply(itr1, itr2);

// Then
assertThat(result)
.isInstanceOf(ChainedIterable.class)
.containsExactly(1, 2, 3, 4, 5, 6);
}

@Test
void shouldMergeHashSets() {
// Given
final HashSet<Integer> hashSet1 = new HashSet<>();
hashSet1.add(1);

final HashSet<Integer> hashSet2 = new HashSet<>();
hashSet2.add(2);
hashSet2.add(3);

IterableMerge<Integer> merger = new IterableMerge<>();
final Iterable<Integer> result = merger.apply(hashSet1, hashSet2);

assertThat(result).containsExactly(1, 2, 3);
}

@Test
void shouldMergeTreeSets() {
// Given
final TreeSet<String> treeSet1 = new TreeSet<>();
treeSet1.add("string1");

final TreeSet<String> treeSet2 = new TreeSet<>();
treeSet2.add("string3");
treeSet2.add("string2");

final IterableMerge<String> merger = new IterableMerge<>();

// When
final Iterable<String> result = merger.apply(treeSet1, treeSet2);

// Then
assertThat(result).containsExactly("string1", "string2", "string3");
}

@Test
void shouldHandleNullElementsOfIterable() {
// Given
final IterableMerge<Integer> merger = new IterableMerge<>();
final List<Integer> itr1 = Lists.newArrayList(1, 2, null, 4);
final List<Integer> itr2 = Lists.newArrayList(null, 6);

// When
final Iterable<Integer> 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<IterableMerge> getDifferentInstancesOrNull() {
return null;
}
}

0 comments on commit f2dead6

Please sign in to comment.