Add StreamZipper
This commit is contained in:
parent
2d58712047
commit
fd9a0a2199
3 changed files with 124 additions and 0 deletions
60
src/main/java/net/kemitix/text/fit/StreamZipper.java
Normal file
60
src/main/java/net/kemitix/text/fit/StreamZipper.java
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
package net.kemitix.text.fit;
|
||||||
|
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.function.BiFunction;
|
||||||
|
import java.util.function.IntFunction;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import static java.lang.Math.min;
|
||||||
|
import static java.util.stream.IntStream.range;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility to zip two {@link Stream}s together.
|
||||||
|
*
|
||||||
|
* @author Paul Campbell (pcampbell@kemitix.net)
|
||||||
|
*/
|
||||||
|
public final class StreamZipper {
|
||||||
|
|
||||||
|
private StreamZipper() {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Zip two {@link Stream}s together.
|
||||||
|
*
|
||||||
|
* <p>The resulting stream will contain only as many items as the shortest of the two lists.</p>
|
||||||
|
*
|
||||||
|
* @param a the first List
|
||||||
|
* @param b the second List
|
||||||
|
* @param zipper the function to zip an item from each list
|
||||||
|
* @param <A> the type of the first list
|
||||||
|
* @param <B> the type of the second list
|
||||||
|
* @param <C> the type of the joined items
|
||||||
|
* @return a Stream of the joined items
|
||||||
|
*/
|
||||||
|
public static <A, B, C> Stream<C> zip(
|
||||||
|
final List<A> a,
|
||||||
|
final List<B> b,
|
||||||
|
final BiFunction<A, B, C> zipper
|
||||||
|
) {
|
||||||
|
return range(0, limit(a, b))
|
||||||
|
.mapToObj(tuple(a, b, zipper));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static <A, B> int limit(
|
||||||
|
final List<A> a,
|
||||||
|
final List<B> b
|
||||||
|
) {
|
||||||
|
return min(a.size(), b.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static <A, B, C> IntFunction<C> tuple(
|
||||||
|
final List<A> a,
|
||||||
|
final List<B> b,
|
||||||
|
final BiFunction<A, B, C> zipper
|
||||||
|
) {
|
||||||
|
return i -> zipper.apply(a.get(i), b.get(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
24
src/main/java/net/kemitix/text/fit/Tuple.java
Normal file
24
src/main/java/net/kemitix/text/fit/Tuple.java
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
package net.kemitix.text.fit;
|
||||||
|
|
||||||
|
public class Tuple<A, B> {
|
||||||
|
|
||||||
|
private final A partA;
|
||||||
|
private final B partB;
|
||||||
|
|
||||||
|
private Tuple(final A partA, final B partB) {
|
||||||
|
this.partA = partA;
|
||||||
|
this.partB = partB;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <A, B> Tuple<A, B> of(final A a, final B b) {
|
||||||
|
return new Tuple<>(a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
public A get1() {
|
||||||
|
return partA;
|
||||||
|
}
|
||||||
|
|
||||||
|
public B get2() {
|
||||||
|
return partB;
|
||||||
|
}
|
||||||
|
}
|
40
src/test/java/net/kemitix/text/fit/StreamZipperTest.java
Normal file
40
src/test/java/net/kemitix/text/fit/StreamZipperTest.java
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
package net.kemitix.text.fit;
|
||||||
|
|
||||||
|
import org.assertj.core.api.WithAssertions;
|
||||||
|
import org.junit.jupiter.api.DisplayName;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.lang.reflect.Constructor;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
class StreamZipperTest implements WithAssertions {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void privateUtilityConstructor() throws NoSuchMethodException {
|
||||||
|
//given
|
||||||
|
final Constructor<StreamZipper> constructor = StreamZipper.class.getDeclaredConstructor();
|
||||||
|
constructor.setAccessible(true);
|
||||||
|
//then
|
||||||
|
assertThatCode(constructor::newInstance)
|
||||||
|
.hasCauseInstanceOf(UnsupportedOperationException.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Pair two lists together")
|
||||||
|
void pairItems() {
|
||||||
|
//when
|
||||||
|
final List<String> strings = Arrays.asList("One", "Two", "Three");
|
||||||
|
final List<Integer> integers = Arrays.asList(3, 2, 1);
|
||||||
|
final List<Tuple<String, Integer>> zipped =
|
||||||
|
StreamZipper.zip(strings, integers, Tuple::of).collect(Collectors.toList());
|
||||||
|
//then
|
||||||
|
assertThat(zipped)
|
||||||
|
.extracting(Tuple::get1)
|
||||||
|
.containsExactlyElementsOf(strings.subList(0, zipped.size()));
|
||||||
|
assertThat(zipped)
|
||||||
|
.extracting(Tuple::get2)
|
||||||
|
.containsExactlyElementsOf(integers.subList(0, zipped.size()));
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue